简体   繁体   中英

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

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?

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; }
}

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. 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);

As you can see from the decompilation in your question, record struct is just a syntactic for struct , so it follows the same rules for constructors, ie struct will always have a default one (unlike class es) and it will be preferred by overload resolution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM