Home > Net >  C# Why is default constructor on new record struct defaulting to default(record)?
C# Why is default constructor on new record struct defaulting to default(record)?

Time:12-28

If I have a record defined as this:

    public record struct MyRecord(string Whatever = "anything"){
        public DateTime  Start {get; init;} = DateTime.UtcNow;
        public DateTime? End   {get; init;}
    }

and then in my code run new MyRecord(), the actual code generated for that is default(MyRecord).

If I supply value for any of the values of the primary constructor (ie, in the parantheses) it correctly calls new MyRecord(whatever).

In this case it leads to the Start value always being 0 ticks (ie 01/01/0001 00:00:00).

SharpLabs

Why is it doing this?

CodePudding user response:

The problem is, that every struct implicitly has a parameterless instance constructor. Therefore, new MyRecord() calls this default constructor instead of your constructor with the optional string parameter.

See: C# 7.0 draft specification / 15 Structs / 15.4 Class and struct differences / 15.4.5 Default values:

[...] Instead, every struct implicitly has a parameterless instance constructor, which always returns the value that results from setting all fields to their default values.

Instead, write your own default constructor (possible since C# 10):

public record struct MyRecord(string Whatever)
{
    public MyRecord()
        : this("anything") // Calls MyRecord(string Whatever)
    {
    }

    public DateTime Start { get; set; } = DateTime.UtcNow;
    public DateTime? End { get; set; }
}

CodePudding user response:

You're using a record struct which is still a struct. When you call the default constructor , you're getting the default value for that struct, just like any other struct.

Structs always have a default constructor that's not the same as any constructor with default parameters. In structs without an explicit default constructor the compiler generates one that initializes all fields to their default values.

When you call new MyRecord() you're calling the default constructor generated by the compiler, not the MyRecord(string) constructor.

If you used this struct :

public  struct Point{
    public int X{get;init;}
    public int Y {get;init;}
    
    public Point(int x=3,int y=3)
    {
        X=x;
        Y=x;
    }            
}
static void Main()
{
    var h = new Point();
    Console.WriteLine(h);
    Console.WriteLine(h with {X = 45} );
    
}

You'd still get the default constructor:

    Point point = default(Point);
    Console.WriteLine(point);
    Point point2 = point;
    point2.X = 45;
    Console.WriteLine(point2);

If you want to override the default constructor you'll have to explicitly define one:

public  struct Point{
    public int X{get;init;}
    public int Y {get;init;}
    
    public Point()
    {
        X=4;
        Y=4;
    }
    public Point(int x=3,int y=3)
    {
        X=x;
        Y=x;
    }            
}

In this case SharpLab shows a call to the type's new default constructor :

    Point point = new Point();
    Console.WriteLine(point);
    Point point2 = point;
    point2.X = 45;
    Console.WriteLine(point2);

CodePudding user response:

As you can see from the decompilation in your question, record struct is just a syntactic for struct "with benefits", so it follows the same rules for constructors, i.e. struct will always have a default one (unlike classes) and it will be preferred by overload resolution:

var h = new MyRecord();
Console.WriteLine(h.Whatever);
Console.WriteLine((h with {End = DateTime.UtcNow}).Whatever );

public struct MyRecord
{
    public MyRecord(string Whatever = "qwe"){this.Whatever = Whatever;}
    public string Whatever {get; init;}
    public DateTime Start  {get; init;} = DateTime.UtcNow.AddDays(-1);
    public DateTime? End {get; init;}
}

Results in the same call to default ctor:

MyRecord myRecord = default(MyRecord);
Console.WriteLine(myRecord.Whatever);
MyRecord myRecord2 = myRecord;
myRecord2.End = DateTime.UtcNow;
Console.WriteLine(myRecord2.Whatever);
  • Related