Why Can't I Define a Default Constructor For a Struct in .Net

Why can't I define a default constructor for a struct in .NET?

Note: the answer below was written a long time prior to C# 6, which is planning to introduce the ability to declare parameterless constructors in structs - but they still won't be called in all situations (e.g. for array creation) (in the end this feature was not added to C# 6).


EDIT: I've edited the answer below due to Grauenwolf's insight into the CLR.

The CLR allows value types to have parameterless constructors, but C# doesn't. I believe this is because it would introduce an expectation that the constructor would be called when it wouldn't. For instance, consider this:

MyStruct[] foo = new MyStruct[1000];

The CLR is able to do this very efficiently just by allocating the appropriate memory and zeroing it all out. If it had to run the MyStruct constructor 1000 times, that would be a lot less efficient. (In fact, it doesn't - if you do have a parameterless constructor, it doesn't get run when you create an array, or when you have an uninitialized instance variable.)

The basic rule in C# is "the default value for any type can't rely on any initialization". Now they could have allowed parameterless constructors to be defined, but then not required that constructor to be executed in all cases - but that would have led to more confusion. (Or at least, so I believe the argument goes.)

EDIT: To use your example, what would you want to happen when someone did:

Rational[] fractions = new Rational[1000];

Should it run through your constructor 1000 times?

  • If not, we end up with 1000 invalid rationals
  • If it does, then we've potentially wasted a load of work if we're about to fill in the array with real values.

EDIT: (Answering a bit more of the question) The parameterless constructor isn't created by the compiler. Value types don't have to have constructors as far as the CLR is concerned - although it turns out it can if you write it in IL. When you write "new Guid()" in C# that emits different IL to what you get if you call a normal constructor. See this SO question for a bit more on that aspect.

I suspect that there aren't any value types in the framework with parameterless constructors. No doubt NDepend could tell me if I asked it nicely enough... The fact that C# prohibits it is a big enough hint for me to think it's probably a bad idea.

Does struct have default constructor?


Does it imply that a struct will have its values initialized through a default hidden constructor?

Yes, in the sense that all member fields will be set to their default(T) values.

In practice, the compiler could just do something like memset(ptr, 0, sizeInBytes) . What actually happens is an implementation detail.

Why struct can not have parameterless constructor

I cannot have an explicit parameterless constructor, only the implicit one, that initializes all members to their default.

Although the CLR allows it, C# does
not allow structs to have a default
parameterless constructor. The reason
is that, for a value type, compilers
by default neither generate a default
constructor, nor do they generate a
call to the default constructor. So,
even if you happened to define a
default constructor, it will not be
called and that will only confuse you.
To avoid such problems, the C#
compiler disallows definition of a
default constructor by the user. And
because it doesn't generate a default
constructor, you can't initialize
fields when defining them, ...


Struct Implicit Default Constructor vs. Parameterless Constructor

The implicit default constructor is the parameterless constructor which is automatically created by the compiler. The reason you can't create a parameterless constructor is because the default one already exists. I don't know why they chose to do it this way, and why you're not allowed to override it.

why is there not always a default constructor

Having a custom constructor (usually) means that the internal state of the object is initialized with some custom information that you provide via constructor parameters. If you still had the default constructor in such a case, what would the initial state be?

If you have no custom constructor then it is assumed to be fine if you just use the default constructor because there is no internal state to initialize.

Why class required default constructor but structure dont required?

There is always a parameterless constructor in a struct - and you can't define your own one. It will always initialize all fields to their default values. This is effectively a requirement of the CLR, although the CLR itself doesn't refer to this as a constructor, and is described in section 11.3.8 of the C# spec. (Although C# doesn't allow you to declare your own parameterless constructor for structs, the CLR does - and it's sometimes called. See my blog post on the topic for more information.)

The value created by calling the parameterless constructor on a struct is always the same as an "uninitialized" value in an array or an instance/static field.

Classes, however, have a different "default" value, as a field (or array element) of a reference type will be null by default. There is no guaranteed way of creating an instance of a class without specifying any values. If you specify any constructors yourself for a class, the C# compiler will not provide a default constructor, as described in section 10.11.4 of the C# spec.

C# struct default values

Update: In C# 10+ (.NET 6+) this limitation is lifted. You now can have default constructors on structs, and you also can initialize fields and properties in place. Write your struct as if it was a class, and it will work:

public struct OptionsStruct
{
public int ItemA { get; set; } = 2;
public int ItemQ { get; set; } = 2;
}
    SetOptions(new OptionsStruct()
{
ItemA = 3,
// ...all other fields have default values.
});

However, there are 2 gotchas to be aware of:

  • If you have no constructors or a parameter-less constructor on your struct, the field and property initializations will work fine. But, they won't work if you have a constructor with parameters but no parameter-less constructors. If you have a with-parameter constructor, also write a parameter-less constructor (even if it's empty), so when you write new MyStruct(), the fields and properties are initialized as you expect. (This behavior is there to keep backward compatibility with the previous behavior of not calling a constructor when all parameters are optional. See the last code block on this answer for an example.)

    public struct NoConstructor
    {
    public int Item { get; set; } = 42;
    }

    public struct ParameterlessConstructor
    {
    public int Item { get; set; } = 42;

    public ParameterlessConstructor() { }
    }

    public struct WithParameterConstructor
    {
    public int Item { get; set; } = 42;

    public WithParameterConstructor(int item)
    {
    Item = item;
    }
    }

    public struct BothConstructors
    {
    public int Item { get; set; } = 42;

    public BothConstructors() { }

    public BothConstructors(int item)
    {
    Item = item;
    }
    }
        Console.WriteLine(new NoConstructor().Item); // 42
    Console.WriteLine(new ParameterlessConstructor().Item); // 42
    Console.WriteLine(new WithParameterConstructor().Item); // 0
    Console.WriteLine(new BothConstructors().Item); // 42
  • The parameter-less constructor is not guaranteed to be always called, so don't rely on your fields and properties being always initialized. If you create an array of a struct, like new MyStruct[5], or if you use default or default(MyStruct), no constructor will be called and the field and properties will be initialized to default values (0 or false or null), just like how it would be before C# 10.

    public struct MyStruct
    {
    public int FortyTwo { get; } = 42;

    public int GetFortyThree()
    {
    return FortyTwo + 1;
    }
    }

    public class SomeClass
    {
    MyStruct myStruct; // not initialized, same as default(MyStruct)

    public int GetFortyThree()
    {
    return myStruct.GetFortyThree();
    }
    }
        Console.WriteLine(new MyStruct().GetFortyThree()); // 43
    Console.WriteLine(default(MyStruct).GetFortyThree()); // 1
    var array = new MyStruct[5];
    Console.WriteLine(array[0].GetFortyThree()); // 1
    Console.WriteLine(new SomeClass().GetFortyThree()); // 1

Here's the link to the docs on the new C# 10 / .NET 6 feature: Parameterless constructors and field initializers

For C# 9 and below, read on...


The limitation on structs is that you cannot have a default constructor. So you cannot set default values to the fields and properties (because that is compiled into the default constructor).

But you can have a non-default constructor, i.e. a constructor that takes parameters.

So you can have a struct like this:

public struct OptionsStruct
{
public int ItemA { get; set; }
public int ItemQ { get; set; }

public OptionsStruct(bool useDefaults)
{
if (useDefaults)
{
ItemA = 2;
ItemQ = 2;
}
else
{
ItemA = 0;
ItemQ = 0;
}
}
}

And use it as you wrote:

    SetOptions(new OptionsStruct(useDefaults:true)
{
ItemA = 3,
// ...all other fields have default values.
});

Another way to go is to have a static method that sets the default values:

public struct OptionsStruct
{
public int ItemA { get; set; }
public int ItemQ { get; set; }

public static OptionsStruct GetDefault()
{
return new OptionsStruct()
{
ItemA = 2;
ItemQ = 2;
};
}
}

And use it like this:

    var options = OptionsStruct.GetDefault();
options.ItemA = 3;
SetOptions(options);

If the number of your properties is not too much, you can also use a constructor with optional parameters:

public struct OptionsStruct
{
public int ItemA { get; set; }
public int ItemQ { get; set; }

public OptionsStruct(int itemA = 2, int itemQ = 2)
{
ItemA = itemA;
ItemQ = itemQ;
}
}

But it will only be called if you give it at least one parameter:

    var options1 = new OptionsStruct(); // The "default" constructor is called, so everythng will be 0.
Console.WriteLine(options1.ItemA); // 0
Console.WriteLine(options1.ItemQ); // 0

var options2 = new OptionsStruct(3); // Everything works as expected.
Console.WriteLine(options1.ItemA); // 3
Console.WriteLine(options1.ItemQ); // 2

Can you have default parameters on a readonly struct in c#?

Counter-intuitively you can't have all default parameters or an explicit parameterless constructor on a struct, this is not limited to readonly struct.

Unlike a class, a struct is value-type and is not required to have a constructor, so in your case you aren't providing any parameters at all, hence the constructor never gets called.

As noted in the documentation

Limitations with the design of a structure type

When you design a structure type, you have the same capabilities as
with a class type, with the following exceptions:

You can't declare a parameterless constructor. Every structure type
already provides an implicit parameterless constructor that produces
the default value of the type.

When you don't supply parameters, the generated IL will call

OpCodes.Initobj Field

Initializes each field of the value type at a specified address to a
null reference or a 0 of the appropriate primitive type.

Furthermore

Unlike Newobj, initobj does not call the constructor method. Initobj
is intended for initializing value types, while newobj is used to
allocate and initialize objects.

In contrast, in the following case it will. Defaults will be initalized the way you expect.

var asd = new ReadonlyStruct(2);

The following generated IL will be

newobj instance void ReadonlyStruct::.ctor(int32, uint8, bool)

OpCodes.Newobj Field

The newobj instruction allocates a new instance of the class
associated with ctor and initializes all the fields in the new
instance to 0 (of the proper type) or null references as appropriate.
It then calls the constructor ctor with the given arguments along with
the newly created instance. After the constructor has been called, the
now initialized object reference (type O) is pushed on the stack.

In short, you may need to rethink your problem or use a static create method.



Related Topics



Leave a reply



Submit