Gene S
Gene S

Reputation: 2793

Mimicing constants using static readonly vs static getter

I am working with a third party control that is using "strange values" to distinguish between a list of choices. They use two different properties to uniquely identify each choice.

Example:
"Field" + "RW" = "CheckedOutBy"
"System" + "N" = "Name"
"Field + "N" = "Notifier"

There are a total of 37 different choices in all (each with a different combination of the two values to make up the 37 unique choices).

I have created a struct that stores the two values, with the idea that I will create a new instance of the struct for each choice.

public struct ColumnCode : IEquatable<ColumnCode>
{
    public static readonly ColumnCode Empty = new ColumnCode();

    private readonly ColumnType _columnType;
    private readonly string _code;

    internal ColumnCode(ColumnType columnType, string code)
    {
        _columnType = columnType;
        _code = code;
    }

    public override string ToString() { ... }
    public bool Equals(ColumnCode other) { ... }
    public override int GetHashCode() { ... }
}

Ideally I would like to create a "constant" for each of the choices, but since constants are not an option I want to try and mimic a constant.

The two approaches I have come up with are to either use a static readonly field or a static property with only a getter.

public static class FieldOption 
{
    public static ColumnCode CheckedOutBy { get; } = new ColumnCode(ColumnType.Field, "XW");
    public static ColumnCode Name { get; } = new ColumnCode(ColumnType.System, "N");
    public static ColumnCode Notifier { get; } = new ColumnCode(ColumnType.Field, "N");
}

or

public static class FieldOption 
{
    public static readonly ColumnCode CheckedOutBy = new ColumnCode(ColumnType.Field, "XW");
    public static readonly ColumnCode Name= new ColumnCode(ColumnType.System, "N");
    public static readonly ColumnCode Notifier = new ColumnCode(ColumnType.Field, "N");
}

In either case I can now refer to the choices in my C# code using FieldOption.CheckedOutBy, FieldOption.Name or FieldOption.Notifier, etc but I am not sure if one approach is better than the other.

Is one of these choices better than the other to mimic a const, or is there a better approach that I am not considering.

I have read a large amount of information on the internet and am still not coming up with a good answer. Some of it seems to be conflicting. Much of the information states to favor properties over fields but then in this article (https://msdn.microsoft.com/en-us/library/ms229057(v=vs.110).aspx) Microsoft says "DO use public static readonly fields for predefined object instances" so I feel static readonly fields is the correct choice.

I am also not sure how reflection falls into play here. I want to make sure that the values for the FieldOptions cannot be changed, even through reflection.

Any help on this would be greatly appreciated.

Upvotes: 2

Views: 988

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70701

I want to make sure that the values for the FieldOptions cannot be changed, even through reflection

The only way to accomplish that would be to use read-only properties, and even then only if you reinstantiate the respective value every time the getter is called, e.g.:

public static ColumnCode CheckedOutBy
{
    get { return new ColumnCode(ColumnType.Field, "RW"); }
}

Using the syntax you've shown, or auto-properties with a private setter, there is still a backing field and that backing field can still be changed through reflection, albeit with slightly more difficulty since the field name is not visible in the source code and has a compiler-implementation-dependent name.

Of course, reinstantiating the value every time the getter is called has negative performance implication. So there's a cost to making the property deeply read-only (i.e. immune to reflection). Whether this performance cost matters in your scenario is something you'll have to determine for yourself. There's no "one right answer" to that question.

I have read a large amount of information on the internet and am still not coming up with a good answer. Some of it seems to be conflicting

That's because, other than scenarios where you have some specific constraint that informs your decision (such as wanting to prevent reflection from being able to change the value), this really is mostly a matter of personal preference. The previously proposed duplicate answer addresses many of the issues that differentiate fields from properties, but as a practical matter in the specific scenario you're asking about, there's very little real difference.

Fields nominally perform better, since they can be accessed directly instead of requiring a method call. But a) in many cases, the method's body will be inlined, negating that advantage, and b) even if the method call exists, it's not really enough overhead to matter or even be measurable in most cases.


So, you need to decide: how badly do you need protection against code modifying these values via reflection? Is it really important enough to make it worth wrapping the values in properties with procedurally-generated values? If you do so, how often will you be accessing these properties? Will it be frequent enough that the overhead of generating the values on-demand every time the getter is called will impact the usefulness of your code?

These are questions only you can answer. It is not possible for someone here to answer that for you.

Upvotes: 2

Related Questions