Initializers of covariant objects?

to say that I have a class that has a property that is a <string, bool> dictionary, using an object initializer, I can use this syntax (which, I think, looks pretty clean):

new MyClass() { Table = { {"test",true},{"test",false} } } 

however, outside the initializer, I cannot do this:

 this.Table = { {"test",true},{"test",false} }; 

Why are initializers a special case? I would venture to suggest that it has something to do with LINQ requirements, covariance or much more, but it feels a bit incompatible, not being able to use this initializer everywhere ...

+6
c # object-initializers
Jan 23 '11 at 12:52
source share
3 answers

The question is somewhat confusing, since the question has nothing to do with LINQ, has nothing to do with general dispersion, and it also has a collection initializer as well as an object initializer. The real question is, as far as I can say, β€œwhy is it not legal to use a collection initializer outside an expression to create an object?”

The relevant design principle here is that, in general, we want the operations that create and initialize the objects to have the word β€œnew” in them somewhere, as a signal to the reader that the creation of the object is taking place here. (Yes, there are a few exceptions to this rule in C #. As an exercise for the reader, see if you can name them all.)

Performing your actions makes it difficult to reason about code. Quickly, what does it do?

 d = new List<int>() { 10, 20, 30 }; d = { 40, 50, 60 }; 

Does the second line add 40, 50, 60 to the existing list? Or is he replacing the old list with the new one? There is no β€œnew” one, and does the reader expect that a new object has been created?

When you speak

 q = new Whatever() { MyList = { 40, 50, 60 } }; 

which does not create a new list; it adds 40, 50, 60 to the existing list as designated by the constructor. Therefore, your proposed syntax is ambiguous and confusing as to whether a new list is created or not.

The proposed function is both confusing and unnecessary, so it is unlikely that it will be implemented in the near future.

+11
Jan 23 '11 at 16:38
source share

This limitation is much older than LINQ. Back in C, you could write

 int numbers[5] = {1, 2, 3, 4, 5}; 

but you cannot use this syntax to assign values ​​to an array.

My guess about the reason for this in C # is that usually you should not use the same link for two different objects. If you need to assign a new collection to an existing link, most likely you have not developed the code very well, and you can either initialize the collection when defining, or use two separate links instead of one.

+2
Jan 23 '11 at 13:00
source share

Given that your syntax raises a NullReferenceException - are you sure you can use it?

 public class Test { public Dictionary<string, bool> Table {get; set;} } public void TestMethod() { Test t = new Test { Table = { {"test", false} } }; //NullReferenceException } 

It will be compiled as follows (through a reflector):

 Test <>g__initLocal3 = new Test(); <>g__initLocal3.Table.Add("test", 0.0M); 

As you can see, Table not initialized, while creating a NullReferenceException at runtime.

If you create a dictionary in ctor Test , the class initializer creates a cascade of Add statements, which is syntactic sugar in the initializer (for IEnumerable s).

This probably was not introduced for normal code due to unforeseen side effects that we cannot see or imagine. Eric Lippert could help, as he probably has a deeper understanding of this issue.

0
Jan 23 '11 at 12:56
source share



All Articles