Having program with such code :
var subtree = new Tree<int>(5, EnumeratorOrder.BreadthFirstSearch) { 1, 2 };
var tree = new Tree<int>(7, EnumeratorOrder.BreadthFirstSearch) { subtree, 10, 15 };
I сan't understan what means { 1, 2 }?
I сan't understan what means { 1, 2 }
The {1, 2} are Collection Initializers.
They represent a short-hand version of
var temp = new Tree<int>(5, EnumeratorOrder.BreadthFirstSearch);
temp.Add(1);
temp.Add(2);
var subtree = temp;
Note regarding initial assignment to temp: The meaning of assignment is evaluate the left, evaluate the right, do the assignment. Evaluating the right produces side effects, and those effects must be ordered before the effect of the assignment. See comments for a full discussion.
It's a collection initializer.
Collection initializers let you specify one or more element initializers when you initialize a collection class that implements IEnumerable or a class with an Add extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the Add method of the class in your source code; the compiler adds the calls.
Related
MSDN states that:
By using a collection initializer you do not have to specify multiple calls to the Add method of the class in your source code; the compiler adds the calls.
They also give this example, using the newer collection initialization syntax with brackets:
var numbers = new Dictionary<int, string> {
[7] = "seven",
[9] = "nine",
[13] = "thirteen"
};
However, when checking the IL code generated, it seems that this code does not at all result in any calls to the Add method, but to rather to one set_item, like so:
IL_0007: ldstr "seven"
IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, string>::set_Item(!0/*int32*/, !1/*string*/)
The "old" syntax with curly brackets in contrast gives the following:
// C# code:
var numbers2 = new Dictionary<Int32, String>
{
{7, "seven"},
{9, "nine"},
{13, "thirteen"}
};
// IL code snippet:
// ----------
// IL_0033: ldstr "seven"
// IL_0038: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, string>::Add(!0/*int32*/, !1/*string*/)
... As you can see, a call to Add is the result, as expected. (One can only assume that the text on MSDN mentioned above is yet to be updated.)
I've so far discovered one case where this difference actually matters, and that is with the quirky System.Collections.Specialized.NameValueCollection. This one allows for one key to point to more than one value. Initialization can be done in both ways:
const String key = "sameKey";
const String value1 = "value1";
const String value2 = "value2";
var collection1 = new NameValueCollection
{
{key, value1},
{key, value2}
};
var collection2 = new NameValueCollection
{
[key] = value1,
[key] = value2
};
... But because of the differences in how only the former actually calls the NameValueCollection::Add(string, string), the results differ when looking at the contents of each collection;
collection1[key] = "value1,value2"
collection2[key] = "value2"
I realize that there's a connection between the old syntax and the IEnumerable interface, and how the compiler finds the Add method by naming convention etcetera. I allso realize the benefits of any indexer type being subject to the new syntax, as discussed in this SO answer before.
Perhaps these are all expected features, from your point of view, but the implications had not occurred to me, and I'm curious to know more.
So, I wonder if there's a source of documentation at MSDN or elsewhere that clarifies this difference in behavior that comes with the choice of syntax. I also wonder if you know of any other examples where this choice may have such an impact as when initializing a NameValueCollection.
I suppose for the ultimate clarification, you have to go to the specification. The C# 6 spec is not 'officially' released, but there is an unofficial draft available.
What's interesting here is that, despite its location in the Programming Guide, the indexer syntax is not a collection initializer, it's an object initializer. From 7.6.11.3 'Collection Initializers':
A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by
commas. Each element initializer specifies an element to be added to the collection object being initialized, and
consists of a list of expressions enclosed by { and } tokens and separated by commas. ... The collection object to which a collection initializer is applied must be of a type that implements
System.Collections.IEnumerable or a compile-time error occurs. For each specified element in order, the
collection initializer invokes an Add method on the target object with the expression list of the element initializer as
argument list
And from 7.6.11.2 'Object Intializers':
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by
commas. Each member_initializer designates a target for the initialization. An identifier must name an accessible
field or property of the object being initialized, whereas an argument_list enclosed in square brackets must specify
arguments for an accessible indexer on the object being initialized.
Take this as an example:
public class ItemWithIndexer
{
private readonly Dictionary<string, string> _dictionary =
new Dictionary<string, string>();
public string this[string index]
{
get { return _dictionary[index]; }
set { _dictionary[index] = value; }
}
}
Note that this class does not meet the requirements to have a collection initializer applied: it does not implement IEnumerable or have an Add method, so any attempt to initialize in this way would result in a compile-time error. This object initializer targeting the indexer will compile and work, however (see this fiddle):
var item = new ItemWithIndexer
{
["1"] = "value"
};
// x is compiled as an int
var x = 10;
// y is compiled as a string
var y = "Hello";
// z is compiled as int[]
var z = new[] { 0, 1, 2 };
but
// ano is compiled as an anonymous type
var ano = new { x1 = 10, y1 = "Hello" };
ano object's properties created are read-only . I want to figure it out why those properties are read only. suggestions are appreciated ?
EDIT:
var ano1 = new { x1 = 10, y1 = "Hello" };
var ano2 = new { x1 = 10, y1 = "Hello" };
Is that if the new anonymous type has the same number and type of properties in the same order will it be of the same internal type as the first ?
var does not mean "use an anonymous type", it means "Compiler, go figure out the type for me!". In the first three cases, the type is actually a "named" type - System.Int32, System.String, and System.Int32[] (in the last case the type of array's elements is also deduced by the compiler from the type of array elements that you put in the initializer).
The last case is the only one where an anonymous type is used. It is by design that C#'s anonymous types are immutable. The primary case for adding them in the language in the first place has been introduction of LINQ, which does not need mutability in cases when anonymous types are produced. In general, immutable classes tend to give designers less problems, especially when concurrency is involved, so designers of the language decided to go with immutable anonymous types.
Anonymous types are immutable, i.e Can't change.
What is an immutable type?
Eric Lippert's Blog
Interesting statement from here. And an alternative is found here.
... [B]y ensuring that the members do not change, we ensure that the
hash is constant for the lifetime of the object.This allows anonymous
types to be used with collections like hashtables, without actually
losing them when the members are modified. There are a lot of benefits
of immutabilty in that, it drastically simplifies the code that uses
the object since they can only be assigned values when created and
then just used (think threading)
If I have a default initializer set, and a define an anonymous one when I create my object. Is the default skipped, or just run before? The reason I want to know is because in the case below, if they are run after, the List object created in the default will be discarded immediately, thus creating unnecessary garbage.
class ArrangedPanel : RectElement
{
public List<RectElement> arrangedChildren = new List<RectElement>();
public int Padding = 2;
}
//Somewhere else
new ArrangedPanel()
{
Padding = 5,
arrangedChildren = new List<RectElement>()
{
new ButtonToggle(),
new ButtonToggle()
}
}
In your example code the Padding = 2 occurs before Padding = 5.
You are unnecessarily creating a List<RectElement>, but I'd challenge you to create a scenario where such unnecessary allocations cause any appreciable performance hit.
arrangedChildren will be set to the last instance you create
for example:
arrangedChildren = new List<RectElement>();
arrangedChildren = new List<RectElement>()
{
new ButtonToggle(),
new ButtonToggle()
}
the arrangedChildren will point to the second list.
If no other object references to the first one it will disapair (GC).
But if some 1 would keep a reference to the first instance it will stay alive and you could have duplicates or two differents lists where you are working on.
This could cause some problems
From the C# Specification, section 17.4.5.2
The instance field variable initializers of a class correspond to a
sequence of assignments that are executed immediately upon entry to
any one of the instance constructors (§17.10.2) of that class. The
variable initializers are executed in the textual order in which they
appear in the class declaration. The class instance creation and
initialization process is described further in §17.10.
Thus the initializations in the body class declaration will be performed first, followed by the initializations in the constructor. This can be observed directly by viewing the IL output.
I'm wondering about the behavior of extension methods in C#. Please see the examples below:
static string ExtendedToString( this object oObj )
{
return "Object";
}
static string ExtendedToString( this Array oArray )
{
return "Array";
}
// Example 1: int array - working as expected.
int[] o = new int[] { 1, 2, 3 };
o.ExtendedToString( ); // returns "Array"
// Example 2: array as object - did not expect the result.
object o = new int[] { 1, 2, 3 };
o.ExtendedToString( ); // returns "Object"
Why is (in the last case) the object's extension method called and not the one for int[]?
Overload resolution is performed at compile time. The compiler sees that o is declared as object, so it calls the overload that takes an object. The fact that o actually contains an array at runtime is irrelevant, because the compiler doesn't know it.
That's actually not specific to extension methods, you would get the same result by calling it as a normal static method (ExtensionsClass.ExtendedToString(o))
You declared o as object:
object o = new int[] { 1, 2, 3 };
thats why:
o.ExtendedToString( ); // returns "Object"
but you can
int[] obj = o as int[];
obj.ExtendedToString( ); // returns "Array"
as the resolution is depending on the (static) type
Because of static typing. Extension methods are rewrited by compiler as if you called them by regular syntax. At the compile time, second object o has the type of Object, so object's extension method is called
Thomas Levesque already has a perfect explanation of why your code doesn't work, so I won't repeat that. The work around is testing at runtime with is or as:
static string ExtendedToString( this object oObj )
{
if(oObj is Array)
return "Array";
else
return "Object";
}
Generally type testing in such a way is a bit of an anti-pattern and you should prefer virtual methods where possible. But in this case it's probably still the best solution since you can't change the Array/Object classes.
If there are many classes which need special treatment you could consider a Type -> Func<object,string> Dictionary.
My question is: What is the most efficient and correct, for large set of data ?
_pointBuffer1 = new Point3DCollection {
new Point3D(140.961, 142.064, 109.300), new Point3D(142.728, 255.678, (...)
-- or --
_pointBuffer1.Add(new Point3D(140.961, 142.064, 109.300)); _poitBuffer1.Add(142.728, (...)
Or is it the same ?
Point3D is declared as a Point3DCollection, but my question is for any object collection (could be Int32 for example) ..
I would strongly suggest using the collection initializer for the sake of clarity (although I'd use some newlines as well).
They don't quite end up as the same IL, mind you. The first ends up being equivalent to:
var tmp = new Point3DCollection();
tmp.Add(new Point3D(140.961, 142.064, 109.300));
tmp.Add(new Point3D(142.728, 255.678));
...
_pointBuffer1 = tmp;
In other words, the assignment to the eventual variable is only made after all the Add calls.
This is important if your Point3D constructor somehow references _pointBuffer1!
Both are compiled to the same IL. Collection initializers are just syntactic sugar. They will call the Add method. Example:
var res = new List<int>() { 1, 2, 3 };
is compiled to:
List<int> <>g__initLocal0 = new List<int>();
<>g__initLocal0.Add(1);
<>g__initLocal0.Add(2);
<>g__initLocal0.Add(3);
List<int> res = <>g__initLocal0;
The only difference is an additional local variable being declared.
Collection initialisation is syntactic sugar. By this I mean that it is a convenient shorthand that is understood by the complier. The compiler will produce code that is logically identical to calling the collection's add method for each element.