I ran into this issue today when creating a struct to hold a bunch of data. Here is an example:
public struct ExampleStruct
{
public int Value { get; private set; }
public ExampleStruct(int value = 1)
: this()
{
Value = value;
}
}
Looks fine and dandy. The problem is when I try to use this constructor without specifying a value and desiring to use the defaulted value of 1 for the parameter:
private static void Main(string[] args)
{
ExampleStruct example1 = new ExampleStruct();
Console.WriteLine(example1.Value);
}
This code outputs 0 and does not output 1. The reason is that all structs have public parameter-less constructors. So, like how I’m calling this() my explicit constructor, in Main, that same thing occurs where new ExampleStruct() is actually calling ExampleStruct() but not calling ExampleStruct(int value = 1). Since it does that, it uses int‘s default value of 0 as Value.
To make matters worse, my actual code is checking to see that int value = 1 parameter is within a valid range within the constructor. Add this to the ExampleStruct(int value = 1) constructor above:
if(value < 1 || value > 3)
{
throw new ArgumentException("Value is out of range");
}
So, as it stands right now, the default constructor actually created an object that is invalid in the context I need it for. Anyone know how I can either:
- A. Call the
ExampleStruct(int value = 1)constructor. - B. Modify how the default values are populated for the
ExampleStruct()constructor. - C. Some other suggestion/option.
Also, I am aware that I could use a field like this instead of my Value property:
public readonly int Value;
But my philosophy is to use fields privately unless they are const or static.
Lastly, the reason I’m using a struct instead of a class is because this is simply an object to hold non-mutable data, should be fully populated when it is constructed, and when passed as a parameter, should not be able to be null (since it is passed by value as a struct), which is what struct’s are designed for.
Actually, MSDN has some good guidance on
structNotice that they are considerations for considering a
struct, and its never a “this should always be a struct”. That is because the choice to use astructcan have performance and usage implications (both positive and negative) and should be chosen carefully.Notice in particular that they don’t recommend
structfor things > 16 bytes (then the cost of copying becomes more expensive than copying a reference).Now, for your case, there is really no good way to do this other than to create a factory to generate a
structfor you in a default state or to do some sort oftrickin your property to fool it into initializing on first use.Remember, a
structis supposed to work such thatnew X()==default(X), that is, a newly constructedstructwill contain the default values for all fields of thatstruct. This is pretty evident, since C# will not let you define a parameterless constructor for astruct, though it is curious that they allow all arguments to be defaulted without a warning.Thus, I’d actually suggest you stick with a
classand make it immutable and just check fornullon the methods that it gets passed to.However, if you absolutely must have a
structfor other reasons – but please consider the costs ofstructsuch as copy-casts, etc – you could do this:Notice that by default, the
Nullable<int>will benull(that is,HasValue == false), thus if this is true, we didn’t set it yet, and can use the null-coalescing operator to return our default of1instead. If we did set it in the constructor, it will be non-null and take that value instead…