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.
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.
Related
I ran into a problem while doing my job, which is porting software from flash AS3 to .NET/Mono. In AS3 code base I can find many Object declarations that are initialized like this:
private const MAPPING:Object =
{
ssdungf:'flydung',
ssdungt:'flydung',
superfutter:'superfeed'
}
The best option for me would be in C# using anonymous type like this:
var MAPPING = new
{
ssdungf = "flydung",
ssdungt = "flydung",
superfutter = "superfeed"
};
The problem is... well let me quote MSDN (source):
You cannot declare a field, a property, an event, or the return type of a method as having an anonymous type
But they don't say why.
So the question remains: why you cannot declare a field and property as having an anonymous type? Why .NET creators stripped it from that option?
I am getting warning here from SO that my question appears subjective, but I think it is not at all - there need to be objective reason for that.
As for me, I don't see any obstacles for that but somehow it is not supported. As compiler can easily generate the type for field or property of class, in a same manner as it does for local variables.
The option for me was to use dynamic type but unfortunately Mono engine I am using is stripped from that.
Also the option for me is to use object type and using later reflection to find these fields:
private static readonly object MAPPING = new
{
ssdungf = "flydung",
ssdungt = "flydung",
superfutter = "superfeed"
};
But using reflection is this situation is dirty I would say.
I tried to find answer, but I really didn't find any. Here are some SO answers to similar questions, but they don't answer why:
Can a class property/field be of anonymous type in C# 4.0?
Declaring a LIST variable of an anonymous type in C#
How do you declare a Func with an anonymous return type?
Why you cannot declare a field and property as having an anonymous type?
Because C# is statically typed, so any memory location has to be given a type, and declaration does so. With locals we can infer from context if its initialised at the same time as declaration with var but that is a shorthand for a type that is usable even when the type hasn't got a name.
What would a field with an anonymous type, that is to say a statically-bound but indescribable type, mean?
dynamic would indeed be the closest analogy to the code you are porting, but since that isn't available to you, you might consider using an IDictionary<string, object> (which incidentally is how ExpandoObject, which is often used with dynamic to have objects that behave more like javascrpt objects, works behind the scenes). This would be slower and less type-safe than if you created a class for the object needed, but can work.
The problem on an anoynmous property is: how do you get/set it?
Suppose it would work:
class MyClass
{
public MyField = new { TheValue = "Hello World" };
}
Now in your consuming code you´d write code to read the code:
MyClass m = new MyClass();
m.MyField.TheValue = "newValue";
How was this different from having a type for MyField? All you´d get is that you can omit two or three lines of code whilst gaining nothing. But I think you might produce many problems as no-one knows what he can assign to/expect from that member.
Furthermore you can´t do much with an anonymous object, basically you can just set it and read it. There are no methods (except Equalsand GetHashCode inherited from object) that you can call so the opportunities are quite low.
Last but not least an anonymous object is usually used as temporaryily, for example within a Select-statement. When you use it you say: this type is going to be used only within the current specific scope and can be ignored by the entire world as internal implementation-detail. Creating a property of an anonymous type will expose such a detail to the outside. Of course you could argue that the designers could at least allow them for private members, but I guess doing so would bypass the complete concept of accessability for nothing.
this is a question that can discussed only, but not really answered.
My question is: I have a complex rendering application and with a lot of primitive data types like:
Color
FontSize
FontFamily
Thickness
...
All of them represent a single value, e.g. Color = Value(uint32), FontFamily = Name(string)
I want to design the datatypes in a way, that they cannot become invalid and that you cannot pass invalid values to a method. They should be immutable.
So my first idea, was to define them as structs, but how to handle the initializers (in a struct you cannot override the default constructor and you cannot have initializers for your fields.
For example: The FontSize must be between 4 and 100.
One solution could be the following design:
struct FontSize
{
readonly in size;
public int Size
{
get { return size >= 4 && size <= 100 ? size : DefaultSize; }
}
public FontSize(int size)
{
Guard.IsBetween(size, 4, 100, nameof(size)); // Throws ArgumentException
this.size = size;
}
}
which means, that
FontSize a;
FontSize b = new FontSize(14);
bool equal = a == b; // True
Which is a little bit strange.
How would you design data types like this?
EDIT: Sorry, I have missed the point, that I would do validation in the constructor. But the problem with structs is that there is still the default constructor. With classes I can have null References.
So the point is, that you can only have
Classes with validation in the constructors => You have to check for Null-Refs and you don't get valid default values for variables and properties
OR
Structs with an ugly property to solve the problem with the default constructor. => No Null Refs, but it looks strange to me.
What you're trying to do is a good thing. If your domain classes are created so that they can't contain invalid data then all of your checking is in one place instead of checking for invalid values wherever the classes are used.
The answer is
Use read-only properties
Pass the values used to populate those values in the constructor
Validate in the constructor
Or if you don't want the validation to exist within the class itself (there could be reasons for that, like much more complicated validations), you could
Still use read-only properties
Make the constructor private
Use a static "create" method. It calls the constructor, creates a new object, validates it (perhaps using some extension method) and then returns either the valid object or throws an exception.
Sorry, one more suggestion - I actually like this one best:
Still use read-only properties
Make the constructor internal
Create a separate builder class in the same assembly as your type. That class is public, but the constructor of your type is internal. That way classes outside the assembly can only access the builder class, pass it the parameters, and then it validates the parameters and either creates a class instance or throws an exception.
Pros
Validation still isn't in your data class
You can have multiple builder classes with different validation parameters. So if you need a different version of your data class that has different validation requirements you don't have to modify that class - you just create a different builder class or add a method to the existing one. But you always have control over how consumers create your class.
Con
Because the constructor is internal other classes in the same assembly can create invalid instances.
To ensure that your data type is never invalid, there is no way to do this other that making it a class type. If you use a struct, you'll never be able to prevent someone from using the default parameterless constructor, which will initialize all fields to their types' default values. A custom constructor doesn't have this problem, because you can set up validation inside the constructor.
FontSize a;
FontSize b = new FontSize(14);
bool equal = a == b; // True
Which is a little bit strange.
Indeed, this looks very odd and may cause a lot of trouble for people using your types. If you insist on using structs, then you may consider adding XML comments (if you're using Visual Studio) to the property stating that a default value will be used if the current value is out of range. This might mitigate the confusion, but surely there will be times when someone doesn't read comments popping up in intellisense.
If you use an initializer list to create a struct, do the members you leave out get a known default value?
public struct Testing
{
public int i;
public double d;
public string s;
}
Testing test = new Testing { s="hello" };
I found a link at Microsoft that implies it but does not state so explicitly: Default Values Table (C# Reference).
A small test program shows that it does not generate a compiler error and produces the expected results. I know better than to rely on simple tests for guarantees though. http://ideone.com/nqFBIZ
Yes, they contain default(T) where T is the type of the value.
Object references will be null.
Excerpt:
As described in Section 5.2, several kinds of variables are
automatically initialized to their default value when they are
created. For variables of class types and other reference types, this
default value is null. However, since structs are value types that
cannot be null, the default value of a struct is the value produced by
setting all value type fields to their default value and all reference
type fields to null.
Taken from here:
http://msdn.microsoft.com/en-us/library/aa664475(v=vs.71).aspx
I remember when studying the MOC for the certification that they explicitly state this. It is a guaranteed feature of the language.
To expand on pid's answer:
test = new Testing { s = hello }
is specified as having the semantics of:
Testing temp = new Testing();
temp.s = "hello";
test = temp;
The default constructor of a value type is documented as the constructor which sets all the fields of the instance to their default values.
More generally, the C# language requires that any constructor of a value type have the property that all fields be definitely assigned before the constructor terminates normally.
Now, if no constructor is called then there are two cases. If the variable is initially assigned then the variable acts the same as though the default constructor was called. For example, if you say
Testing[] test = new Testing[1];
Then test[0] is initialized to the default value the same as if you'd said
Testing[] test = new Testing[1] { new Testing() };
If the variable is not initially assigned, for example, a local variable, then you are required to definitely assign all the fields before you read them. That is, if we have a local:
Testing test;
test.s = "hello";
Console.WriteLine(test.d); // ERROR, test.d has not been written yet.
Note also that mutable structs are a worst practice in C#. Instead, make a public constructor that sets all the fields, make the fields private, and put property getters on top of them.
Is it possible to enforce rules or throw an error when using object initializers in C#? I'd like to throw a compiler error or warning if an object is initialized but is missing a certain property.
public class Party
{
public string Name { get; set; }
public string Date { get; set; }
public Location Location { get; set; }
}
public class SignUpForParty
{
public void DoSomething()
{
Party party = new Party()
{
Name = "New Years Party!",
Date = "Dec 31, 1999"
// Show WARNING/ERROR here because no Location given
};
}
}
Essentially, I'm looking for a way to ensure that all objects of type Party are created with valid data for every instance.
Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.
Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty
Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.
Object initializers really shouldn't be considered alternatives to writing a constructor.
You should always include constructors in your types if you have requirements like this. It is a good idea to create a default set of constructors (or use optional arguments on one constructor) which at least provide a guarantee that the object will always be created in a valid, meaningful state.
Object initializers are helpful for optional properties, but shouldn't be relied upon for requirements of your type itself.
You cannot force every property to be initialized with an object initializer.
Even if you could, a consumer of the object could provide default (0, null, ...) values. Depending on your needs, consider validating object state at key times (e.g. before it can be saved to a database).
If you go that route, have a look at the IDataErrorInfo interface.
If your type is not valid when only 2 properties are set then you need to fix your design, not emit an error.
You provide a default constructor, which tells me that I don't have to set anything to use the object after initialization. You provide getters and setters for each property, again, implicitly telling users of your class that it is ok to set on but not the other.
If this is not the case then I suggest you provide a constructor which forces me to supply all three values. Yes, I can still use (null, null, null), but you could check for that and throw an error.
Also, if PropertyA is dependent on PropertyB then either
A) Only one of them should have a setter, or
B) There should be logic in the setter of each to properly initialize the other after the value changes.
This is a design problem, not a language problem. You cannot force the initializer syntax to work differently than how it was spec'd.
Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty
Code isn't supposed to be 'pretty', it is supposed to work. Even then, a constructor which takes a few arguments is 'ugly'? Huh? Don't buy into the hipster nonsense, write code that works and works well.
The only way I could see this implemented is if there was some event (or equivalent) that was raised when the object initializer was completed. There is currently a Connect request for something to this effect.
Unfortunately, I didn't make the cut for .NET 4.5:
Thank you for your suggestion.
This is a great idea, and has the nice property that it doesn't add to the language surface - it just makes object initializers smarter. In principle that would probably make it a breaking change, but that is something we can look into.
Unfortunately we cannot add any more to the release we are currently building, so I am going to resolve as Won't fix for this release. However, I am capturing the suggestion on our list of features for future discussion.
Thanks again!
Mads Torgersen, C# Language PM
Maybe it'll make it's way into .NET 5+.
What about Code Contracts?. This will assert not only that you assigned a value, but you could also specify valid ranges.
Or for check at runtime with debug builds only, you could use Debug.Assert(...) calls to achieve the same as above.
Hi I use initializer block in C#
new Something { foo = 1, bar = 2 };
but people say this is bad practice.
I don't think it is wrong, is it?
You need to ask yourself whether your type should be mutable or not. Personally, I like immutable types - they make it easier to reason about what's going on, easier to validate (once the constructor has been called and the state validated, you know it's not going to become invalid) and they're great for concurrency.
On the other hand, object initializers are certainly useful in cases where it is reasonable to have mutable types. As an example, ProcessStartInfo is effectively used as a builder type for Process. It's useful to be able to write:
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
Indeed, you can even do all this inline instead of having an extra variable. My Protocol Buffers port uses the same sort of pattern:
Foo foo = new Foo.Builder {
FirstProperty = "first",
SecondProperty = "second"
}.Build();
Now one alternative to the builder pattern is constructor parameters (possibly via factory methods). The historical downside of this is that you needed different overloads depending on which properties were being set, and if several parameters had the same type it could be hard to tell which was which. C# 4 makes this significantly easier using optional parameters and named arguments. For example, if you're building an email class you could have:
Email email = new Email(
from: "skeet#pobox.com",
to: "jon#example.com",
subject: "Test email",
body: textVariable
);
This has many of the same benefits of object initializers in terms of clarity, but without the mutability penalty. The constructor call above may have missed out some optional parameters such as attachments and a BCC list. I think this will prove to be one of the biggest benefits of C# 4 for those of us who like immutability but also like the clarity of object initializers.
It's questionable (I won't say "bad") practice to use initialization blocks as a substitute for the appropriate constructor overload, if one exists.
public class Entity
{
public Entity()
{
}
public Entity(int id, string name)
{
this.ID = id;
this.Name = name;
}
public int ID { get; set; }
public string Name { get; set; }
}
If you have this very simple class, then it is generally preferable to write:
var entity = new Entity(1, "Fred");
...than it is to write:
var entity = new Entity { ID = 1, Name = "Fred" };
There are at least two good reasons for this:
You don't know exactly what the constructor is doing. It's possible that, in some circumstances, it might be significantly more expensive to construct the object and then set public properties vs. passing the values through the constructor itself. (You may know that this is not the case, but as the consumer of a class, you shouldn't presume to know care about the implementation details, because they are subject to change).
Your code won't break if one or more of those properties have their names changed, or become read-only (which the ID probably should have been in the first place, but perhaps wasn't due to architectural constraints like that of an ORM).
However, there is one case where you have to use initializers instead of overloaded constructors, and that is when chaining selects in a Linq to SQL/EF query:
var bars =
from f in ctx.Foo
select new Bar { X = f.X, Y = f.Y };
var bazzes =
from b in bars
select new Baz { ... };
This can actually fail with a "no supported mapping" if you use constructor overloads instead of default constructors + initializers. This is, however, a constraint of the technology being used (and an undesirable one at that), and not a coding style issue.
In other cases, you should prefer the constructor overload over the initializer.
If there is no useful/relevant constructor overload that can do the same thing as your initializer, then go ahead and write the initializer, there's nothing wrong with it. The feature exists for a good reason - it makes the code easier to write and read.
but people say is bad practice.
Who says this? At the very least, that’s a controversial statement.
It seems to be all the rage at the moment, and many prominent C# blogs use it extensively.
The advantage over using a constructor is that it’s more readable since the code clearly shows which properties get assigned what values. Compare:
var x = new Something { Foo = 1, Bar = 2 };
with
var x = new Something(1, 2);
Furthermore, if no appropriate constructor is present, the code is more concise than manually assigning to properties:
var x = new Something();
x.Foo = 1;
x.Bar = 2;
Personally, I prefer immutable objects (i.e. objects that, once created, cannot be changed). Unfortunately, the initializer blocks cannot be used in conjunction with such objects (at the moment) because to make this pattern work the object has to have property setters, which an immutable object doesn’t have.
But as long as the object used isn’t immutable I don’t see a compelling reason against using the initializer notation.
Initializer blocks are GREAT practice for the following reasons:
You get to create an object and override its properties before getting its reference
this.ObjA = new ObjA
{
Age = 20,
Name = "123",
};
// this.ObjA will not be set until properties have all been defined
// - safer when multithreading
The parameter-less constructor can still do things behind the scene
(e.g. initialize state members).
You can use in conjunction with constructors with parameters
this.ObjA = new ObjA(20)
{
Name = "123",
};
Using parameter-less constructors is better for (de)serializing scenarios
You can create various objects, change their state via GUI, serialize them, deserialize them elsewhere.
This practice forces authors to write more robust code - where the order in which things are done is less lightly to cause the application to crash every time the class's metadata is changed.
There is nothing wrong with initializer blocks, but if your type for example has many properties, and only a couple of them need to be set on every instance, then you should make them required in a constructor.
The user of your class will know that they can't create an object without specifying those values.
The properties that are essential for the object work, should be initialized in the constructor, so you should provide the appropiate parameters in hthe contstructor.
Initializer blocks are very handy for several of the new features of C# 3.0, but you should keep in mind, that they are not here for replace the parameters in the constructor.
I think it's good.
Because it reduces your typing a lot