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.
Related
When using IEnumerable I'm trying to avoid multiple enumerations. I know I can just use LINQ's .ToList() and be done with it, but that can be a lot of unnecessary list creation. I'd like to:
check and see if the underlying type is a List, and if so return that instance, otherwise
.ToList() it and return the new List
My thought was to use something akin to:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo(IEnumerable<T> enumerable)
{
var list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}
... but it appears from the documentation that the as operator just performs a cast, which would create a new List rather than returning the underlying one, would it not?
If so, how can I retrieve the underlying list instead of creating a new one?
The as operator does not create a new list. It only checks type and perform cast if type is compatible.
The code in the post is logically correct and matches how many LINQ methods are implemented (for example see source of Enumerable.Count which casts to ICollection to see if it can skip enumeration of items).
Note that it is important to cast to correct generic version of list or maybe one of its interfaces - IList would work if you must use non-generic version. Beware of the fact that List<T> is not co/contra-variant and type must match exactly unlike in case of covariant IEnumerable<out T> where you can cast parameter to IEnumerable<TBase> if IEnumerable<TDerived> passed.
Maybe you wanted to do this:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo<T>(IEnumerable<T> enumerable)
{
List<T> list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}
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");
I'm returning a Json'ed annonymous type:
IList<MyClass> listOfStuff = GetListOfStuff();
return Json(
new {
stuff = listOfStuff
}
);
In certain cases, I know that listOfStuff will be empty. So I don't want the overhead of calling GetListOfStuff() (which makes a database call).
So in this case I'm writing:
return Json(
new {
stuff = new List<ListOfStuff>()
}
);
which seems a bit unnecessarily verbose. I don't care what type of List it is, because it's empty anyway.
Is there a shorthand that can be used to signify empty enumerable/list/array? Something like:
return Json(
new {
stuff = new []
}
);
Or have I been programming JavaScript too long? :)
Essentially you want to emit an empty array. C# can infer the array type from the arguments, but for empty arrays, you still have to specify type. I guess your original way of doing it is good enough. Or you could do this:
return Json(
new {
stuff = new ListOfStuff[]{}
}
);
The type of the array does not really matter as any empty enumerable will translate into [] in JSON. I guess, for readability sake, do specify the type of the empty array. This way when others read your code, it's more obvious what that member is supposed to be.
You could use Enumerable.Empty to be a little more explicit:
return Json(
new {
stuff = Enumerable.Empty<ListOfStuff>()
}
);
Although it isn't shorter and doesn't get rid of the type argument.
dynamic is also a better option when dealing with an anonymous type
Enumerable.Empty<dynamic>()
this worked well for me
You might not care what type of list it is, but it matters to the caller. C# does not generally try to infer types based on the variable to which it is being stored (just as you can't create overloads of methods on return type), so it's necessary to specify the type. That said, you can use new ListOfStuff[0] if you want an empty array returned. This has the effect of being immutable (in length) to the caller (they'll get an exception if they try to call the length-mutating IList<T> methods.)
Yes, there is. You have to define an array with as least one element, and use linq to filter the array leaving no elements. Example:
var foo = new
{
Code = 1,
Name = "Bar",
Value = (float?)5.0
};
//use an empty object (or any object) to define the type of the array
var emptyArrayOfFooType = new[] {
new
{
Code = (int)0,
Name = (string)null,
Value = (float?)null
}
}.Where(e => false).ToArray(); //use linq to filter the array leaving no elements
//you can use an existing anonymous type variable too
var anotherEmptyArray = new[] { foo }.Where(e => false).ToArray();
//this array with one element has the same type of the previous two arrays
var fooArray = new[] { foo };
//all arrays have the same type, so you can combine them
var combinedArrays = emptyArrayOfFooType.Concat(anotherEmptyArray).Union(fooArray);
send a generic type?:
List<Object>()
or send an empty object array: new Object[0]
I guess you are talking about C# here. My knowledge is limited in C# but I don't think you can create a new object with no type. Why can't you return a generic new List[] ? (might be mixing Java generics here, am not sure is one can return a generic type list in 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.
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)