Battle
Battle

Reputation: 816

Initialize elements with brackets like Lists in c#

I was thinking about arrays and lists and wondering if and how classes can get an implementation to be initializable like them. Let's take this class as basis:

class TestClass
{
    private List<int> Numbers = new List<int> ();

    // Insert code here
}

What I would like to be able to do is to take the given values and internally fill my list.

TestClass test = new TestClass () { 2, 4, 7, 10 };

What would be normally possible is this:

List<int> test = new List<int> () { 2, 4, 7, 10 };

But I would like to have it for my own custom classes. The next question, which is optional, is if the same can be done for this syntax:

TestClass test = { 2, 4, 7, 10 };

I assume that is less likely to be possible. Note, these are different from this:

Cat cat = new Cat() { Name = "Sylvester", Age=8 };

These are direct and optional declarations of internal fields and properties.

See also MSDN for more info.

Upvotes: 10

Views: 6096

Answers (4)

Glubus
Glubus

Reputation: 2855

To answer your second subquestion: if it is possible to do

TestClass test = { 2, 4, 5, 7 };

I don't think this is correct syntax anywhere. However you could create something that looks like it using the implicit operator.

Since you can instantiate an int array like this: new[] {1,2,3,4}, you can create the following in your TestClass.

public class TestClass {
   private IEnumerable<int> list;
   public TestClass(IEnumerable<int> _list) {
       this.list = _list;
   }

   public static implicit operator(int[] input) {
        return new TestClass(input.ToList());      
   }
}

Then create a new TestClass like this; TestClass testClass = new[] {1,2,3};

Upvotes: 1

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

Technically, the minimum requirements are

  1. IEnumerable interface (of course, IEnumerable<T> is a better choice)
  2. Add method

Minimum example (demonstration only):

  class TestClass: System.Collections.IEnumerable {
    public void Add(int value) { }

    public IEnumerator GetEnumerator() {
      // Just to demonstrate, do not do this in production code
      return null;
    }
  }

  ...

  TestClass myTest = new TestClass() {1, 2, 3};  

In your case:

  class TestClass: IEnumerable<int> {
    private List<int> Numbers = new List<int>();

    // This is required
    public void Add(int value) {
      Numbers.Add(value);
    }

    public IEnumerator<int> GetEnumerator() {
      return Numbers.GetEnumerator();
    }

    // This is required
    IEnumerator IEnumerable.GetEnumerator() {
      return GetEnumerator();
    }
  }

Upvotes: 4

laptou
laptou

Reputation: 6981

As stated here, collection initialisers will work on any class that implements IEnumerable and has an Add() method.

class TestClass : IEnumerable<int>
{
    private List<int> Numbers = new List<int> ();

    public void Add(int n)
    {
        Numbers.Add(n);
    }

    // implement IEnumerable methods down here ...

    public IEnumerator<int> GetEnumerator() => Numbers.GetEnumerator();

    // etc ...
}

Note that if you have more than one parameter in your Add() method signature, then you can enclose them in curly braces to use collection initialiser syntax.

class TestClass2 : IEnumerable<(int, int)>
{
    private List<int> Numbers = new List<(int, int)> ();

    public void Add(int x, int y)
    {
        Numbers.Add((x, y));
    }

    // implement IEnumerable methods down here ...

    public IEnumerator<(int, int)> GetEnumerator() => Numbers.GetEnumerator();

    // etc ...
}

Would be used like this:

var test = new TestClass2 { {2, 3}, {4, 5} };

Upvotes: 13

Patrick Hofman
Patrick Hofman

Reputation: 156938

You just need an Add method to make this work and implement the IEnumerable interface:

class TestClass : IEnumerable<int>
{
    private List<int> Numbers = new List<int> ();

    public void Add(int n)
    {
        Numbers.Add(n);
    }

    public IEnumerator<int> GetEnumerator()
    {
        return Numbers.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

The compiler will recognize the collection initializer syntax and will try to find a matching Add method.

Upvotes: 8

Related Questions