10

I am going through C# 9 new features which will be released soon. Init-Only properties are being introduced with it.

The one big limitation today is that the properties have to be mutable for object initializers to work: They function by first calling the object’s constructor (the default, parameterless one in this case) and then assigning to the property setters.

Init-only properties fix that! They introduce an init accessor that is a variant of the set accessor which can only be called during object initialization:

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

With this declaration, the client code above is still legal, but any subsequent assignment to the FirstName and LastName properties is an error. What does this line mean? If ReadOnly also does the same thing then what is use of Init-Only property.

Daniel A. White
  • 181,601
  • 45
  • 354
  • 430
vivek nuna
  • 16,885
  • 12
  • 74
  • 152
  • 2
    "which will be released soon" - where you get this idea from? So far nothign is implemented or available even as experimental. They say it will mostly work only with .NET 5.0 and upward, but this does NOT MEANT IT WILL RELEASE IN THE SAME TIMEFRAME. In fact, logically, they could release it in 2040 "and it needs at .east .NET 5.0". To my knowledge there is no indication given as to when we can play with these fetures, even on an experimental level. – TomTom Jun 14 '20 at 12:30
  • 1
    @Supergibbs Its completely ok, It was really a good practical question. But some people are good at pulling others' legs. – vivek nuna Jun 17 '20 at 13:57

3 Answers3

14

As stated in the new C# 9 features post,

The one big limitation today is that the properties have to be mutable for object initializers to work: They function by first calling the object’s constructor (the default, parameterless one in this case) and then assigning to the property setters.

However, value types with readonly modifiers are immutable as stated in readonly documentation.

Therefore, it is not possible to use readonly properties with object initializers.

However, with Init-only properties you can use object initializers.

emre nevayeshirazi
  • 18,455
  • 11
  • 60
  • 81
  • Thank you, so other than this difference, both will be same in all aspects? Or in other words can I say to use object initializer to readonlty properties they have come up with Init_Only properties? – vivek nuna Jun 14 '20 at 12:52
  • I think this is the main reason for the implementation of this new feature but without more information about the implementation details, I am not sure. – emre nevayeshirazi Jun 14 '20 at 12:57
  • Can you provide example which shows the difference between the two – vivek nuna Jun 14 '20 at 13:06
  • 1
    @viveknuna Go and watch https://mybuild.microsoft.com/sessions/fc099bf7-8c85-4c3b-9a90-2d917342f945?source=schedule . – mjwills Jun 14 '20 at 13:31
  • With init, Callers can use property initializer syntax to set the values, while still preserving the immutability (readonly properties). – M.Hassan Mar 05 '22 at 15:12
8

The purpose of Init-only properties is to allow assignation only in the object initializer or the constructor for your class.

If we consider your Person class, assigning to FirstName or LastName is allowed in the constructor or in the object initializer but you can't assign to FirstName or LastName in other places :

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }

    // this is a constructor
    public Person()
    {
        this.FirstName = "first name"; // works
        this.LastName = "last name"; // works
    }
}

//this is a random method
public SomeMethod()
{
    Person myPerson = new Person
    {
        FirstName = "first name", // works
        LastName = "last name" // works
    };

    myPerson.FirstName = "change the first name"; // Error (CS8852)
    myPerson.LastName = "change the last name"; // Error (CS8852)
}
nalka
  • 1,345
  • 9
  • 22
  • This isn't a good example though: **if** `Person`'s constructor never assigns to `LastName` and if you do `Person p = new Person() { FirstName = "bob" }` (and _never_ assign to `LastName`) then the program has unwittingly violated the `class Person`'s contract because `LastName` is now `null` despite being typed as `String` (not `String?`), which throws-off C#'s nullable-reference-type checking abilities. – Dai Feb 18 '22 at 06:16
  • @Dai I don't understand why you're saying it's not a good example, "if Person's constructor never assigns to LastName..." Well first of all it's not the case here. Secondly, there's a second condition : having nullable enabled. And if despite all these conditions someone happens to be in the situation you described, CS8616 will let them know there's a problem – nalka Feb 19 '22 at 15:11
  • CS8616 only applies to reference-types - if you're using value-types or have `#nullable` disabled in your `.csproj` then the compiler won't give you any warnings at all. – Dai Feb 19 '22 at 15:13
  • Well that's one more condition (and again it's not met in my example). Indeed, CS8616 won't pop, but you'll get [CS0843](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0843?f1url=%3FappId%3Droslyn%26k%3Dk(CS0843)). If you're disabling nullable well nullable-reference-type checking abilities don't exist so there's no point in having CS8616. – nalka Feb 19 '22 at 15:24
  • CS0843 only applies to `struct` types, not classes. – Dai Feb 19 '22 at 15:25
  • Yeah so you'll have CS0843 with structs and CS8616 otherwise – nalka Feb 19 '22 at 15:29
  • No, that is incorrect: CS0843 is when a `class` has unassigned non-nullable reference-type members, while CS0843 is when a `struct` has unassigned members (regardless of being reference-types or value-types), _not_ when a `class` has unassigned `struct` or other value-type members (that's when you don't get any warnings at all, which is dangerous when the `default(TValue)` a value-type is meaningful, e.g. `enum` values. – Dai Feb 19 '22 at 15:36
-2

Unlike set an init-only property can only be set in the constructor or by using a property initializer.