Question

I've had a hard time figuring out how I can write a struct in C# that has constraints on its fields' values. For example, System.DateTime

DateTime d = new DateTime();

puts the value 01/01/0001 12:00:00 AM in d. But I can't write an explicit parameterless constructor, as structs are not allowed to have an explicit parameterless constructor. So, how can I create a struct that will be default constructed within the constraints I want?

The only thing I could think of was to design properties such that they return values within the constraints I want. For example, if I store an int that I want to be greater than 0 I just add one to the return value and disallow setting to less than 1. Is this the sensible route to take?

Was it helpful?

Solution

See the answer to this question for additional info. Basically, without parameters, value type fields are always initialized to default values as a performance optimization, since value types are often used in bigger numbers in arrays etc.

You should consider creating a class if you want true constraints, but "smart properties" may be the way to go if performance is in question when using your class. As for the DateTime type, yes, it does "smart" properties, storing the date as a number which is converted to specific format upon request (access via properties). The 01/01/0001 12:00:00 AM is actually the representation of the default internal 0, by design.

OTHER TIPS

I think you`d better suggest using a class in that situation. Put this struct into it, and in parameterless constructor you can explicitly set value you want your struct to contain.

Do you need value type semantics? What's wrong with a plain old immutable class?

I recommend using Reflector to examine exactly how the DateTime struct was written. That should give you the insight you need.

Part of value type semantics in CLR is that a value type always has a reasonable valid default value (and furthermore, that reasonable default value is represented by a default-initialized value type, using the normal initialization rules). If this isn't the case for your type, then it should not be a struct.

DateTime sets its default value to DateTime.Min. When you print it out (which defers to its ToString() method), its current value is printed, which is that.

Here's an example:

class Program
{
    static void Main(string[] args)
    {
        ChrisTime t = new ChrisTime();
        Console.WriteLine(t);

        DateTime time = new DateTime();
        Console.WriteLine(time);

        Console.Read();
    }
}

public struct ChrisTime
{
    private int _length;

    public int Length
    {
        get
        {
            return _length;
        }
        set
        {
            _length = value;
        }
    }

    public override string ToString()
    {
        return Length.ToString();
    }

}

Prints out:

0
01/01/0001 00:00:00

But if you try initializing _length to 1, it will fail as you can't do that nor set constructors. However the ToString method of DateTime performs:

public override string ToString()
{
    return DateTimeFormat.Format(this, null, DateTimeFormatInfo.CurrentInfo);
}

You are seeing the fields of the DateTime formatted into a string format. So the day, month, year, hour, minute, second all at zero as you'd expect with a newly constructed object.

The DateTime struct has constraints on it's value because all value setting is done via method calls. Notice all properties on DateTime are readonly.

so...

public struct BetweenNegativeFiveAndFive
{
    public static readonly int MinValue;
    public static readonly int MaxValue;
    int _value;
    public int Value
    {
        get { return _value; }
    }
    public int Add(int a)
    {
        int b = _value + a;
        if (b >= MinValue && b <= MaxValue)
            _value = b;
        return _value;
    }
    static Foo()
    {
        MinValue = -5;
        MaxValue = 5;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top