Initializing a Generic.List in C# - c#

In C#, I can initialize a list using the following syntax.
List<int> intList= new List<int>() { 1, 2, 3 };
I would like to know how that {} syntax works, and if it has a name. There is a constructor that takes an IEnumerable, you could call that.
List<int> intList= new List<int>(new int[]{ 1, 2, 3 });
That seems more "standard". When I deconstruct the default constructor for the List I only see
this._items = Array.Empty;
I would like to be able to do this.
CustomClass abc = new CustomClass() {1, 2, 3};
And be able to use the 1, 2, 3 list. How does this work?
Update
Jon Skeet answered
It's calling the parameterless
constructor, and then calling Add:
> List<int> tmp = new List<int>();
> tmp.Add(1); tmp.Add(2); tmp.Add(3);
> List<int> intList = tmp;
I understand what is does. I want to know how. How does that syntax know to call the Add method?
Update
I know, how cliche to accept a Jon Skeet answer. But, the example with the strings and ints is awesome. Also a very helpful MSDN page is:
Object and Collection Initializers (C# Programming Guide)

This is called a collection initializer. It's calling the parameterless constructor, and then calling Add:
List<int> tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
List<int> intList = tmp;
The requirements for the type are:
It implements IEnumerable
It has overloads of Add which are appropriate for the argument types you supply. You can supply multiple arguments in braces, in which case the compiler looks for an Add method with multiple parameters.
For example:
public class DummyCollection : IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
throw new InvalidOperationException("Not a real collection!");
}
public void Add(string x)
{
Console.WriteLine("Called Add(string)");
}
public void Add(int x, int y)
{
Console.WriteLine("Called Add(int, int)");
}
}
You can then use:
DummyCollection foo = new DummyCollection
{
"Hi",
"There",
{ 1, 2 }
};
(Of course, normally you'd want your collection to implement IEnumerable properly...)

Read Object and Collection Initializers (C# Programming Guide). Basically you could this with every custom type that is a list (implements IEnumerable).

They're called collection initializers (also see here), and the way they work is by looking for an Add() method that can do their bidding. It calls Add() for each of the integers you have in your curly braces.
The search for the Add() method is pure compiler magic. It's hardcoded to find a method of that name.

The name you're loooking for is "Collection Initializer". It works under the hood by looking for a method named Add on the collection type and calling it for every value that you specify.
More details: Object and Collection Initializers (C# Programming Guide)

I believe it's a shortcut to the .Add method. I've never tried to override it, though, so I don't know if it's possible.

It's actually using the .Add method. Meaning it's calling .Add for each item in the brackets inside of the constructor.

As far as I'm concerned, the addition of items via object initialization searches a method Add. So, as List<int> will have void Add(int), it will work.
To use it in your class, just add
class CustomClass {
public void Add(int num) {
// Your code here
}
}
Your class should implement IEnumerable, as Hallgrim pointed out.

Related

Create a generic method for list and array

How can I create a generic method so the return type is either a list or an array?
Now for this method I get this error:
(string, int)[]' must be a non-abstract type with a public
parameterless constructor in order to use it as parameter 'T' in the
generic method 'T TournamentsAnalytics.GetParameters()
private void Test()
{
var parameters = GetParameters<List<(string, int )>>();
var parameters2 = GetParameters<(string, int)[]>();
}
private T GetParameters<T>() where T: ICollection<(string, int)>, new()
{
var parameters = new T
{
("nr1", 1),
("nr2", 2),
("nr3", 3),
("nr4", 4),
("nr5", 5),
("nr6", 6)
};
return parameters;
}
You probably should not use generics for this. You could for example just use LINQ to convert a sequence of values to a list or an array:
GetParameters().ToList();
GetParameters().ToArray();
...
private IEnumerable<(string, int)> GetParameters(){
yield return ("nr1", 1);
yield return ("nr2", 2);
...
This seem like it is both much shorter and simpler than messing around with generics. Or just return either a list or an array, and use LINQ to convert to the other type if needed, for small lists created infrequently any inefficiencies will be irrelevant.
There might be ways to use generics if you have some specific issue to solve, For example delegating the creation of the collection to the caller by injecting a delegate: Func<IEnumerable<(string, int)>, T), but it will likely just make things more complicated.
Note that your example uses a collection initializer, and this will just not work with arrays, since this initializer uses the Add-method, and this will just not work for arrays.
The constructor of the Array class is private, and as a result you can't pass an array type into a method with a generic new() constraint.
Arrays can still be created in a few ways using the new keyword:
var cars = new Car[3]; // no Car objects created (yet)
var cars = new[] { new Car(), new Car() }; // initialized
var cars = new Car[] { new Car(), new Car() }; // initialized
This is special syntax for arrays, and you'll see that the syntax is also different from what you are trying to make work in the generic method.
I am assuming that the new calls are converted by the compiler to call the static Array.CreateInstance method (which then calls the private constructor), followed by initializing the entries as needed.

What is this syntax using new followed by a list inside braces?

Ive just seen a piece of code that uses a generic list class to instantiate itself in the following manner:
var foo = new List<string>(){"hello", "goodbye"};
The curly braces after the contructor are especially confusing. It reminds me somewhat of
var bar = new string[]{"hi","bye"};
but in the past i've wouldve always used:
var foo = new List<string>(new []{"hello", "goodbye"});
Has anybody got a link explaining the syntax in the first line of code? I wouldnt even know where to begin with googling it.
As others have pointed out, that is a collection initializer. Some other features you might not be aware of that were added to C# 3:
A collection initializer constructor may omit the parentheses if the argument list is empty. So new List<int> { 10, 20, 30 } is fine.
An array initialized with an array initializer may in some cases omit the type. For example, var myInts = new[] { 10, 20, 30}; infers that myInts is int[].
Objects may be initialized using a similar object initializer syntax. var c = new Customer() { Name = "Fred" }; is the same as var temp = new Customer(); temp.Name = "Fred"; var c = temp;
The point of these features is to (1) make more things that used to require statements into things that require only expressions; LINQ likes things to be expressions, and (2) to enable richer type inference, particularly for anonymous types.
Finally: there has been some confusion in some of the answers and comments regarding what is required for a collection initializer. To be used with a collection initializer the type must (1) implement IEnumerable (so that we know it is a collection) and (2) have an Add method (so that we can add stuff to it.)
See
http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx
for additional thoughts on the design of the feature.
here you go. The keyword is "Array Initializers".
http://msdn.microsoft.com/en-us/library/aa664573(v=vs.71).aspx
or rather "Collection Initializers"
http://msdn.microsoft.com/en-us/library/bb384062.aspx
This is a collection initializer: http://msdn.microsoft.com/en-us/library/bb384062.aspx
The type so initialized must implement IEnumerable and have an Add method. The items in the curly-brace list are passed to the add method; different items in the list could be passed to different Add methods. If there's an Add overload with more than one argument, you put the multiple arguments in a comma-separated list enclosed in curly braces.
For example:
class MyWeirdCollection : IEnumerable
{
public void Add(int i) { /*...*/ }
public void Add(string s) { /*...*/ }
public void Add(int i, string s) { /*...*/ }
//IEnumerable implementation omitted for brevity
}
This class could be initialized thus:
var weird = new MyWeirdCollection { 1, "Something", {5, "Something else"} };
This compiles to something like this:
var temp = new MyWeirdCollection();
temp.Add(1);
temp.Add("Something");
temp.Add(5, "Something else");
var weird = temp;
In his blog post (link posted by Eric Lippert in the comments), Mads Torgersen expresses this concisely:
The list you provide is not a “list of elements to add”, but a “list of sets of arguments to Add methods”. ...[W]e do separate overload resolution against Add methods for each entry in the list.
In the third line of code you provided you are making a new string array, and then passing that string array to the list. The list will then add each of those items to the list. This involves the extra overhead of allocating the array, populating it, and then discarding it.
There is a mechanism for a class to define how to use Collection Initializers to populate itself. (See the other answers) I have never found the need to utilize this for my own classes, but existing data structures such as List, Dictionary, often define them, and they are useful to use.
This is a collection initializer. You can use it on collections with an Add method.
The pair of parentheses before the curly braces is optional.
This is very convenient, because you can use it on collections other than lists, for example on dictionaries:
var x = new Dictionary<int,string> {{1, "hello"}, {2, "world"}};
This lets you avoid a lengthier initialization sequence:
var x = new Dictionary<int,string>();
x.Add(1, "hello");
x.Add(2, "world");

IEnumerable<object> a = new IEnumerable<object>(); Can I do this?

I want to create a new instance of an object IEnumerable<object>
Can I do this?
IEnumerable<object> a = new IEnumerable<object>();
You can for example create an instance of List<object>, which implements IEnumerable<object>. Example:
List<object> list = new List<object>();
list.Add(1);
list.Add(4);
list.Add(5);
IEnumerable<object> en = list;
CallFunction(en);
Another solution would be to use Empty<T>.
msdn extract:
Returns an empty IEnumerable that has the specified type argument.
IEnumerable<object> a = Enumerable.Empty<object>();
There is a thread on SO about it: Is it better to use Enumerable.Empty() as opposed to new List to initialize an IEnumerable?
If you use an empty array or empty list, those are objects and they are stored in memory. The Garbage Collector has to take care of them. If you are dealing with a high throughput application, it could be a noticeable impact.
Enumerable.Empty does not create an object per call thus putting less load on the GC.
Since you now specified you want to add to it, what you want isn't a simple IEnumerable<T> but at least an ICollection<T>. I recommend simply using a List<T> like this:
List<object> myList=new List<object>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
You can use myList everywhere an IEnumerable<object> is expected, since List<object> implements IEnumerable<object>.
(old answer before clarification)
You can't create an instance of IEnumerable<T> since it's a normal interface(It's sometimes possible to specify a default implementation, but that's usually used only with COM).
So what you really want is instantiate a class that implements the interface IEnumerable<T>. The behavior varies depending on which class you choose.
For an empty sequence use:
IEnumerable<object> e0=Enumerable.Empty<object>();
For an non empty enumerable you can use some collection that implements IEnumerable<T>. Common choices are the array T[], List<T> or if you want immutability ReadOnlyCollection<T>.
IEnumerable<object> e1=new object[]{1,2,3};
IEnumerable<object> e2=new List<object>(){1,2,3};
IEnumerable<object> e3=new ReadOnlyCollection(new object[]{1,2,3});
Another common way to implement IEnumerable<T> is the iterator feature introduced in C# 3:
IEnumerable<object> MyIterator()
{
yield return 1;
yield return 2;
yield return 3;
}
IEnumerable<object> e4=MyIterator();
No you can't since IEnumerable is an interface.
You should be able to create an empty instance of most non-interface types which implement IEnumerable, e.g.:-
IEnumerable<object> a = new object[] { };
or
IEnumerable<object> a = new List<object>();
No, You cannot do that. Use the following line of code instead:
IEnumerable<int> usersIds = new List<int>() {1, 2, 3}.AsEnumerable();
I hope it helps.
The main reason is we can't create object of an interface, and IEnumerable is an interface.
We need to create object of the class which implements the interface. This is the main reason we can't directly create object of IEnumerable.
You can do this:
IEnumerable<object> list = new List<object>(){1, 4, 5}.AsEnumerable();
CallFunction(list);
I wanted to create a new enumerable object or list and be able to add to it.
This comment changes everything. You can't add to a generic IEnumerable<T>. If you want to stay with the interfaces in System.Collections.Generic, you need to use a class that implements ICollection<T> like List<T>.
No IEnumerable is an interface, you can't create instance of interface
you can do something like this
IEnumerable<object> a = new object[0];
It's a pretty old question, but for the sake of newcomers, this is how we can protect an IEnumerable<T> from a null exception. Another word, to create an empty instance of a variable of type IEnumerable<T>
public IEnumerable<T> MyPropertyName { get; set; } = Enumerable.Empty<T>();
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.empty?view=net-5.0
Cheers.
I have been Implementing IEnumerable of type IEnumerable<T> by this way
IEnumerable<T> MyEnum = new T[]{ /*object of type T*/ };
Example:
var Object = new Book{id = 1,name = "Hello World"};
IEnumerable<Book> MyEnum = new Book[]{ Object };

IList<IWhatever> as a method parameter

I have two IList<ICat> and I'm trying to create a method which takes an IList<ICat> and does some work. I'm having problems trying to pass either an IList<PussyCat> or IList<OtherCat> to it, both PussyCat and OtherCat implement ICat.
I've tried:
List<PussyCat> cats = ...
DoWork((IList<ICat>)cats);
and just
DoWork(cats);
But neither compile. Any ideas?
C# generics are invariant. It means List<string> is not a List<object>.
C# 4.0 introduces safe covariance/contravariance but still, you wouldn't be able to pass List<string> as List<object>. The reason is:
List<string> x = new List<string>();
List<object> o = x; // assume this statement is valid
o.Add(5); // Adding an integer to a list of strings. Unsafe. Will throw.
Arrays, on the other hand are covariant. You can pass a string[] to a method that expects object[].
There are two alternatives:
Make your method like this:
public void DoWork< T > (IList< T > cats_) where T : ICat
{
//Do work;
}
The other possibility is to have a method like
public void DoWork(IList< ICat > cats_)
{
//Do work;
}
and call it in the following manner:
{
//....Assuming: IList<PussyCat> iListOfPussyCats
List<PussyCat> pussyCats = new List<PussyCats>(iListOfPussyCats);
DoWork(pussyCats.ConvertAll<ICat>( c => c as ICat);
}
If the method doesn't truly require direct indexing (IList<T>) and doesn't require adding/removing items (ICollection<T>), then pass an IEnumerable<T>. The Cast<T>() extension methods allow casting any IList of [insert ICat-derived type] to be passed as an IEnumerable<ICat>.
Till C# 4.0 arrives which has support for co and contra variance you might be able to get away with something like this:
public void DoWork(IEnumerable<ICat> cats)
{
//do something
}
List<PussyCat> pussyCats = new List<PussyCat>;
List<OtherCat> otherCats = new List<OtherCat>;
DoWork(pussyCats.OfType<ICat>);
DoWork(otherCats.OfType<ICat>);

Linq return IEnumerable<MyObject>, how to return MyListObject instead?

Is there a way without looping all the IEnumerable to get back the data inside the object (that inherited BindingList)?
MyListObject--> Transformed with Linq --> Back the data inside MyListObject
I know that I can do .ToList but it doesn't do what I would like.
Any idea? Thank :)
I'm not sure exactly what your requirements are, especially the bit about ToList not doing what you need.
Unfortunately, BindingList<T> only accepts an IList<T> parameter in its constructor and not an IEnumerable<T>.
However, if you implement a pass-through constructor on your custom collection (or if it already has a constructor that takes IList<T>) then you could do something similar to this:
public class MyListObject<T> : BindingList<T>
{
public MyListObject() : base() { }
public MyListObject(IList<T> list) : base(list) { }
}
// ...
MyListObject<int> yourList = new MyListObject<int> { 1, 2, 3, 4, 5 };
yourList = new MyListObject<int>(yourList.Select(s => s * 2).ToList());
// yourList now contains 2, 4, 6, 8, 10
One option is to wrap the returned IEnumerable into your collection type by using/adding constructor that takes IEnumerable as CStick suggest. Perhaps a bit more ellegant way is to add an extension method for the IEnumerable type that would return your collection:
static MyListObject ToMyList(this IEnumerable<T> en) {
// construct your MyListObject from 'en' somehow
}
// And then just write:
var mylist = (from c in ... ).ToMyList()
The last option that's probably too complicated for this simple scenario is to implement all the LINQ query operators for your type (extension methods Where, Select, and many many others). The plus thing is that you could (maybe) do some things more efficiently, but it's really a bit difficult thing to do.
Most lists accept a range of objects in the constructor. Will that work?
Dim objects = 'Linq statement returning IEnumberable array.
Dim mlo As New MyListObject(objects)

Categories