Classes that implement IEnumerable
and provide a public void Add(/* args */)
function can be initialized like in the following example:
List<int> numbers = new List<int>{ 1, 2, 3 };
which calls the Add(int)
function 3x after initializing the List<int>
.
Is there a way to define this behavior explicitly for my own classes? For example, could I have the initializer call a function other than the appropriate Add()
overload?
Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression, or an object initializer.
Initializers execute before the base class constructor for your type executes, and they are executed in the order in which the variables are declared in your class. Using initializers is the simplest way to avoid uninitialized variables in your types, but it's not perfect.
An object initializer is an expression that describes the initialization of an Object . Objects consist of properties, which are used to describe an object. The values of object properties can either contain primitive data types or other objects.
Everything in C# is associated with classes and objects, along with its attributes and methods. For example: in real life, a car is an object. The car has attributes, such as weight and color, and methods, such as drive and brake. A Class is like an object constructor, or a "blueprint" for creating objects.
No, the compiler requires a method named Add
for the collection initializer to work. This is defined in C# specification and cannot be changed:
C# Language Specification - 7.5.10.3 Collection Initializers
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 anAdd
method on the target object with the expression list of the element initializer as argument list, applying normal overload resolution for each invocation. Thus, the collection object must contain an applicableAdd
method for each element initializer. [emphasis mine]
Of course, the Add
method can take more than one argument (like Dictionary<TKey, TValue>
):
dic = new Dictionary<int, int> { { 1, 2 }, { 3, 4 } }; // translated to: dic = new Dictionary<int, int>(); dic.Add(1, 2); dic.Add(3, 4);
Adding just as a sample answer of what works. AFAIK, only Add will work. Code snippet taken from Marius Schulz
// simple struct which represents a point in three-dimensional space public struct Point3D { public readonly double X; public readonly double Y; public readonly double Z; public Point3D(double x, double y, double z) { X = x; Y = y; Z = z; } } // implementation of a collection of points, which respects // the compiler convention for collection initializers and // therefore both implements IEnumerable<T> and provides // a public Add method public class Points : IEnumerable<Point3D> { private readonly List<Point3D> _points; public Points() { _points = new List<Point3D>(); } public void Add(double x, double y, double z) { _points.Add(new Point3D(x, y, z)); } public IEnumerator<Point3D> GetEnumerator() { return _points.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } // instantiate the Points class and fill it with values like this: var cube = new Points { { -1, -1, -1 }, { -1, -1, 1 }, { -1, 1, -1 }, { -1, 1, 1 }, { 1, -1, -1 }, { 1, -1, 1 }, { 1, 1, -1 }, { 1, 1, 1 } };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With