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
struct OptionsStruct { public static OptionStruct Default(int itemA = 2, int itemB = 2) { return new ... } }and use it like:SetOptions(OptionStruct.Default(itemB: 4))item Qin the example I meant to demonstrate that I'd like to tweak -any- field, not just a couple specific ones. Will clarify in question.