I had this C# structure that was building in VS2022 literally up until last night when I upgraded from version 17.0.5 to 17.1
internal struct RoutineSettings
{
public bool Show { get; set; } = true;
public ShapeType PreferredShapeType { get; set; } = ShapeType.None;
}
(ShapeType is just an enum).
After the upgrade, I get this error:
error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
The explanation is straightforward enough. But since this code executed just fine before I am confused.
If the correct answer is #2, it begs the question why is this a requirement? Why is it needed? Because when I "fixed" it, the fix seemed pointless. I just added an empty default constructor:
internal struct RoutineSettings
{
public RoutineSettings() { }
public bool Show { get; set; } = true;
public ShapeType PreferredShapeType { get; set; } = ShapeType.None;
}
And now my code builds again. Why would I need this when it does nothing?
This really appears to have been a compiler bug in the previous version. Up to C# 9.0, structs where not allowed to have a default ctor, and it really was not generated, unlike for classes, where the default ctor was automatically generated when no constructor was defined. This allows to create value types without calling code (by just nullifying the memory). So apparently, they wanted to make this change explicit, because it really makes a difference in the code generated, whether the default constructor exists or not. Do note that in your example, the default constructor is not empty, because any field initializers are implicitly added to the constructor code. So in C# 10, when the constructor is declared, it is generated, otherwise it is left away from the generated IL.
Also note that there are a bunch of pitfalls when using this feature. The default ctor is still not executed when allocating an array of the struct:
[Fact]
public void StructCtorIsExecuted()
{
var r = new RoutineSettingsWithDefaultCtor();
Assert.Equal(10, r.PreferredShapeType);
RoutineSettingsWithDefaultCtor[] array = new RoutineSettingsWithDefaultCtor[10];
Assert.Equal(0, array[0].PreferredShapeType); // <-- When allocating an array, the default ctor is NOT executed
}
internal struct RoutineSettingsWithDefaultCtor
{
public RoutineSettingsWithDefaultCtor()
{
PreferredShapeType = 10;
}
public bool Show { get; set; } = true;
public int PreferredShapeType { get; set; } = 2;
}
}
some more problems are described here: https://davidshergilashvili.space/2021/09/05/c-10-struct-type-can-define-default-constructor/
That's not a bug, but rather a new design choice for C#:
https://github.com/dotnet/sdk/issues/23971
Solution:
Define a public parameter-less constructor and it will solve the issue.
For example, before:
public struct Abc
{
public int Num1 = 5;
}
After:
public struct Abc
{
public int Num1 = 5;
public Abc() {} // <--- Parameter-less default constructor
}