Reputation: 816
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.
Upvotes: 10
Views: 6096
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
Reputation: 186668
Technically, the minimum requirements are
IEnumerable
interface (of course, IEnumerable<T>
is a better choice)Add
methodMinimum 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
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
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