Reputation: 13575
For example, I have an immutable type
class Contact
{
// Read-only properties.
public string Name { get; }
public string Address { get; }
}
And I hope I can use object initializer syntax to create a Contact
Contact a = new Contact { Name = "John", Address = "23 Tennis RD" };
But I cannot. Any possible way to make use of the powerful object initializer syntax in this case?
Upvotes: 7
Views: 1387
Reputation: 41
This is dated now, but with the release of C# 9 you can use init
to achieve the desired functionality.
So your example would become:
class Contract
{
// Read-only properties.
public string Name { get; init; }
public string Address { get; init; }
}
And then you could initialize with:
// success!
Contract a = new Contract { Name = "John", Address = "23 Tennis RD" };
But you would still be unable to modify the parameters after setting them (so effectively they are still readonly).
// error!
a.Name = "Uncle Bob";
Under the hood, when you use object initializer syntax prior to C# 9 the compiler would call the default constructor first, and then set the property values you've specified. Obviously if those properties are readonly (i.e. only a get
method), it can't set them. The init
only setter allows setting the value only on initialization, either via a constructor method or object initializer syntax.
More info is available here: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#init-only-setters
Upvotes: 4
Reputation: 97778
The closest thing would be a constructor with optional parameters:
class Contact
{
public string Name { get; }
public string Address { get; }
public Contact(string name = null, string address = null) {
Name = name;
Address = address;
}
}
Then you can call it with parameter names:
new Contact(
name: "John",
address: "23 Tennis RD"
)
The syntax is slightly different from an object initializer, but it's just as readable; and IMO, the difference is a good thing, because constructor parameters tend to suggest immutable properties. And you can specify the parameters in any order, or leave some out, so it's just as powerful as object initializer syntax.
This does require some extra code (defining the constructor, assigning all the properties), so it's more work than object initializer syntax. But not too terrible, and the value of immutable objects is worth it.
(For what it's worth, C# 7 may get immutable "record types" that have much simpler syntax. These may or may not make it into the final release, but they sound pretty cool.)
Upvotes: 5
Reputation: 4572
Nope, you cannot use it with readonly properties.
Here are the different property and field types in comparism.
public class sometype {
public int readonlyProp{
get;
}
public int normalProp {
get;
set;
}
public const int constField = 3;
public readonly int readonlyField = 3;
public int normalField = 3;
public void test() {
sometype test = new sometype() { readonlyProp = 3}; // Doesn't work -> Property or indexer is readonly
sometype test1 = new sometype() { normalProp = 3 }; // ok
sometype test2 = new sometype() { constField = 3 }; // Doesn't work -> Static field or property
sometype test3 = new sometype() { readonlyField = 3 }; // Doesn't work -> readonly field
sometype test4 = new sometype() { normalField = 3 }; // ok
}
}
It is important to understand that const fields are considered static and thus are not instance members. And since the object initializer is used for instance members this doesn't work.
Upvotes: 1
Reputation: 6408
Object initializer will first construct the object, then set property values. It needs setters.
It's short hand for:
Contact a = new Contact();
a.Name = "John";
a.Address = "23 Tennis RD";
A readonly field can't have it's values set once the object has been constructed. To have that class immutable, you'll need to create a constructor to take those values:
class Contact // Immutable class
{
// Read-only properties.
public string Name { get; }
public string Address { get; }
public Contact(string name, string address)
{
this.Name = name;
this.Address = address;
}
}
Upvotes: 0