6

Disclaimer for re-opening

This question is about object validation of an immutable object during construction using C# 9 init-only setters (as opposed to using a constructor with verbose "boiler plate code").


C# 9 introduces an option to initialize immutable object with object initializer syntax, using init only setters:

class Immutable
{
   public string Name { get; init; }
   public int Value { get; init; }
}

Immutable o = new Immutable { Name = "Value1", Value = 257 };

Additionally it introduces a nice syntax to create mutated copies of an object:

var o1 = o with { Value = 65537 };

Previously the only option to create and initialize a new immutable object was to use constructor with parameters. The new option is more natural and elegant, but one important feature of constructor initialization is missing: validation. With constructor I can be sure to never create an object with invalid state.

It is possible to put validation code into init setters, but there's no way, of which I'm aware of, to provide a general validation of object state as a whole. Specifically, I don't see any way to assure in the example above that Name property will fulfill its contract to have a non-null value. As parameterless constructor is necessary to use object initializer syntax, it is possible to create an uninitialized instance:

var o = new Immutable();

in which case properties will get default values.

Question [edit]: is there any method to validate immutable object state after initialization with init setters is complete? Keep in mind that property assignments may be not specified in the initialization statement and the default object state may be invalid.

  • `Specifically, I don't see any way to assure in the example above that Name property will fulfill its contract to have a non-null value.` Could you show us your attempt to do that with init setters? – mjwills Dec 19 '20 at 05:46
  • 2
    "As parameterless constructor is necessary to use object initializer syntax" - not in C#... are you sure you are not talking about something else? – Alexei Levenkov Dec 19 '20 at 07:21
  • @MickyD, when initializing object via constructor parameters I can validate all of them in separation, but also in relation with each other. Of course, I could invoke such validation from all relevant setters, but it is not as good, and the scenario I'm most interested in is a specific case when I don't specify any properties when creating an object (no setters are invoked). My main problem: when I create an immutable object with initialization via constructor parameters I can guarantee that any created object is valid. I can't guarantee that using parameterless constructor and init setters. – Jacek Ostrowski Dec 21 '20 at 09:02
  • 1
    @mjwills, Name property is non-nullable string (with #nullable enable), so it's value after default initialization is invalid. I can assure that null can't be assigned via setter, but I can't assure that some valid value is assigned at all. I could assure that using constructor with parameters. – Jacek Ostrowski Dec 21 '20 at 09:10
  • @AlexeiLevenkov, public constructor is necessary to create object (or protected if invoked from descendant class) - it can be implict, auto-generated by compiler, it can also have parameters with default values, but it has to exist. It is invoked before init setters. – Jacek Ostrowski Dec 21 '20 at 09:11
  • You should try something like `new MyClass(123, "test") { Prop3 = "Here"};` to see if your "parameterless constructor is necessary" stands. (Obviously it has nothing to do with the problem you trying discuss but it distracts from the question in a same way as adding SQL injection as example code for some unrelated problem) – Alexei Levenkov Dec 21 '20 at 09:26
  • @AlexeiLevenkov, I know that it can also be a constructor with parameters (possibly with default values). It's not the point - the point is that constructor must be public and it will be executed before (possible, but not mandatory) property assignments. Therefore I can't use it to verify object state after initialization with init setters is complete. – Jacek Ostrowski Dec 21 '20 at 11:24
  • @MickyD, so you think that init setters can only be used for optional properties? In other words in my example above I should use constructor instead, as both properties are not optional? – Jacek Ostrowski Dec 22 '20 at 05:30
  • After reading your question again and doing some research I see what you mean now. It looks like the jury at Microsoft is still out on this one. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/init#questions. I agree with you validation is easy during the old-constructor-way and yes re the new style: _how would an `init` property know whether it can validate the object or not, it might not have been set yet. How can we access the object create/init session?_ Don't know... –  Dec 22 '20 at 06:55

1 Answers1

2

I've finally found the information on validation in Mads Torgersen's comment under his post on C# 9. They are looking into options to introduce this in C# 10.

[Edit] If was finally, at least partially, resolved in C# 11 by introduction of required keyword, which can be used on properties. This is quite elegant solution, because it forces assignment on source code level (IDE hilights missing assignments). Still, ability to run some code after all assignments have been made would be useful.

  • C# 10 has been released and this feature is not there. Does anybody know where I can track the status? – Xiaoguo Ge Mar 16 '22 at 06:44
  • @XiaoguoGe, your question made me look for a proposal, but I can't find it, unfortunately, in [C# proposals](https://github.com/dotnet/csharplang/tree/main/proposals). But I'm pretty sure I read some mention of it as an upcoming feature after C# 10 was released. – Jacek Ostrowski Mar 23 '22 at 06:18