Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create an array-like C# constructor that will allow "new MyClass() { obj1, obj2, obj3 };"

I'm trying to create a class that accepts a constructor similar to that of a dictionary, list, or array where you can create the object with a literal collection of objects, though I have been unable to find how to create such a constructor, if it's even possible.

MyClass obj = new MyClass()
{
    { value1, value2 },
    { value3, value4 }
}
like image 363
CosworthTC Avatar asked Mar 29 '11 01:03

CosworthTC


2 Answers

You need two things to make collection initializers work:

  1. Implement IEnumerable (non-generic version)
  2. Add() method that matches the collection initializer

Here's an example that looks like IDictionary:

class Program
{
    static void Main(string[] args)
    {
        MyClass obj = new MyClass()
        {
            {value1, value2},
            {value3, value4}
        };
    }
}

public class MyClass : IEnumerable
{
    public void Add(object x, object y)
    {

    }

    public IEnumerator GetEnumerator()
    {
    }
}

Note that the collection initializer code literally translates to this:

MyClass temp = new MyClass();
temp.Add(value1, value2);
temp.Add(value3, value4);
MyClass obj = temp;

Because of the temp variable, if any of the Add() calls generate an exception, the named variable (obj in this case) is never actually assigned. Interestingly, this also means that if MyClass were to implement IDisposable, then Dispose() would not get called on the constructed object when one of the Add() methods generates an error (I tested this to be sure).

Why require IEnumerable? Because that interface differentiates classes with Add for collections and classes with Add for calculations.

http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx

[when you analyze classes with Add] you realize that there are essentially two fundamentally different meanings of the name “Add”:

a) Insert the argument into a collection, or

b) Return the arithmetic sum of the argument and the receiver

Also note that if your collection class implements IDisposable, then you should not use collection initializers if there is any chance that Add() will throw an exception or if any of the expressions being fed to Add() can throw an exception.

https://connect.microsoft.com/VisualStudio/feedback/details/654186/collection-initializers-called-on-collections-that-implement-idisposable-need-to-call-dispose-in-case-of-failure#

like image 147
Samuel Neff Avatar answered Oct 02 '22 22:10

Samuel Neff


How about a variable constructor:

public class MyClass
{
    public MyClass() {}
    public MyClass(params object[] list) { ... }
}
like image 28
Richard Schneider Avatar answered Oct 03 '22 00:10

Richard Schneider