Get values from an enum into a generic List - c#

I don't know how to convert the following line from VB to C#:
Dim values As New List(Of T)(System.Enum.GetValues(GetType(T)))
My version doesn't work:
List<T> values = new List<T>(System.Enum.GetValues(typeof(T)));
The best overloaded method match for
'System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable)'
has some invalid arguments
The constructor-parameter doesn't take it that way - what cast (or else) am I missing?
For clarification: It is wrapped up within the following generic method
public static void BindToEnum<T>()
{
List<T> values = new List<T>(System.Enum.GetValues(typeof(T)));
//...
}

Using LINQ:
List<T> list = System.Enum.GetValues(typeof(T))
.Cast<T>()
.ToList<T>();

Just add a .Cast<T>():
List<T> values = new List<T>(System.Enum.GetValues(typeof(T)).Cast<T>());

Based on this post, I created myself a function to do this for me; It's great in Unit Tests when you want to loop through all values of an Enum to verify something only works on certain values.
public static IEnumerable<T> GetEnumValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
Then I can use it like so:
var values = GetEnumValues<SomeTypeCode>();
var typesToAlwaysShow = values.Where(ScreenAdapter.AlwaysShowThisType).Select(q => (int)q).ToList();
Assert.Equal("101,102,105,205", string.Join(",", typesToAlwaysShow));

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.

How Can I Retrieve the Underlying List of an IEnumerable Without Creating a New List?

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
}

Retrieving Anonymous Object's Property in C#

I have the following code
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<object> list = new List<object>();
list.Add(new {
Value = 0
});
//Console.WriteLine(list[0].Value);
}
}
Is there a simple way to write the commented line of code without causing a compile time error? I know I could resort to using the dynamic keyword or implementing an extension method for the Object class that uses Reflection, but is there maybe another more acceptable way?
The goal is the avoid creating a class since its only purpose would be to store data. But at the same time still be able to retrieve the data later on in the program. This code will eventually end up in a web method which is why I want it to be dynamic / anonymous in the first place. All of the objects would end up having the same properties, as they would be storing values stored in tables, but the values are needed later for other calculations.
Is there a simple way to write the commented line of code without causing a compile time error?
Not with the way you've declared the list. If your list will contain only objects of that anonymous type, you could use an array initializer and convert it to a List<{anonymous type}>:
var list = (new [] {
new { Value = 0 }
}).ToList();
Console.WriteLine(list[0].Value);
The nice thing is that you can add to the list easily, since anonymous types with the same properties are merged into one type by the compiler:
list.Add(new {Value = 1});
Per Servy's comment, a method to avoid an array creation would just be:
public static List<T> CreateList<T>(params T[] items)
{
return new List<T>(items);
}
usage:
var list = CreateList(new { Value = 0 });

Create an enumeration of one

If I want an empty enumeration, I can call Enumerable.Empty<T>(). But what if I want to convert a scalar type to an enumeration?
Normally I'd write new List<string> {myString} to pass myString to a function that accepts IEnumerable<string>. Is there a more LINQ-y way?
You can use Repeat:
var justOne = Enumerable.Repeat(value, 1);
Or just an array of course:
var singleElementArray = new[] { value };
The array version is mutable of course, whereas Enumerable.Repeat isn't.
Perhaps the shortest form is
var sequence = new[] { value };
There is, but it's less efficient than using a List or Array:
// an enumeration containing only the number 13.
var oneIntEnumeration = Enumerable.Repeat(13, 1);
You can also write your own extension method:
public static class Extensions
{
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
yield return item;
}
}
Now I haven't done that, and now that I know about Enumerable.Repeat, I probably never will (learn something new every day). But I have done this:
public static IEnumerable<T> MakeEnumerable<T>(params T[] items)
{
return items;
}
And this, of course, works if you call it with a single argument. But maybe there's something like this in the framework already, that I haven't discovered yet.

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>);

Categories