Return list <T> with different contents depending on T
I want to do something like this:
public List<T> GetList<T>() { if (typeof(T) == typeof(Type1)) { return new List<Type1>() { new Type1(), new Type1(), new Type1() }; } if (typeof(T) == typeof(Type2)) { return new List<Type2>() {new Type2(), new Type2()}; } throw new Exception("Unknown T"); } public void DoStuffWithGenericList<T>() { var list = GetList<T>(); // do stuff that does not depend on T } But this, of course, is not legal. I feel like I'm missing something basic here :)
In my case, I get lists of objects of different types from the Entity Framework, but the rest of my logic does not depend on the actual type. It can just work with List or it can be generic.
All Ts that GetList () will call with a type parameter inherit from the same base class, if that matters.
public List<T> GetList<T>() { if (typeof(T) == typeof(Type1)) { return new List<Type1>() { new Type1(), new Type1(), new Type1() }.Cast<T>().ToList(); } if (typeof(T) == typeof(Type2)) { return new List<Type2>() {new Type2(), new Type2()}.Cast<T>().ToList(); } throw new Exception("Unknown T"); } Why not use the βnewβ operator to instantiate types:
public List<T> GetList<T>() where T : new() { if (typeof(T) == typeof(Type1)) { return new List<T>() { new T() }; } // etc... throw new Exception("Unknown T"); } All you have to do is make sure your types can be created by adding a new () constraint.
Code like this cannot work, because it depends on checking the type of runtime (you explicitly specified them). But how can the compiler know at compile time that the result of your runtime checks will be what List<T> actually is?
In this particular example case, you can achieve your desired goal with
public List<T> GetList<T>() where T : new() { if (typeof(T) == typeof(Type1)) { return new List<T>() { new T(), new T(), new T() }; } if (typeof(T) == typeof(Type2)) { return new List<T>() { new T(), new T() }; } throw new Exception("Unknown T"); } But, of course, this does not solve any practical problem. If you have a specific question other than βwhy this does not work,β you must edit the question to submit it.
Consider this: to use GetList at some point in your code, you will need to write
var x = GetList<SomeType>(); A parameter of type SomeType must be hard-coded on the call site, otherwise the program will not compile. But if it must be hard-coded, then the above does not differ from
public List<SomeType> GetListOfSomeType() { return new List<SomeType>(); } var x = GetListOfSomeType(); So what are you trying to accomplish exactly?
Of course, this counter example is somewhat superficial, and in fact, the general version of GetList will allow you to increase flexibility if you want to use reflection. But then again, in your example this is not the case.
Whenever I am going to see if(typeof(T) == typeof(SomeType) , I will switch to a dictionary that looks more or less like this:
public static class ListCreator { private static readonly Dictionary<Type, Func<object>> _Creators; static ListCreator() { _Creators = new Dictionary<Type, Func<object>>(); InitializeDefaultCreators(); } public static List<T> Create<T>() { Func<object> creator; if (!_Creators.TryGetValue(typeof(T), out creator)) { throw new InvalidOperationException("No creator available for type " + typeof(T).FullName); } return (List<T>)creator(); } public static void Register<T>(Func<List<T>> creator) { _Creators.Add(typeof(T), creator); } public static void Register(Type type, Func<object> creator) { _Creators.Add(type, creator); } public static bool Unregister<T>() { return _Creators.Remove(typeof(T)); } public static bool Unregister(Type type) { return _Creators.Remove(type); } private static void InitializeDefaultCreators() { Register(MyDoubleListCreator); Register(typeof(int), () => Enumerable.Range(1, 15).ToList()); } private static List<double> MyDoubleListCreator() { return Enumerable.Range(1, 10).Select(Convert.ToDouble).Select(val => val + 0.3).ToList(); } } This can be used as follows:
internal class Program { private static void Main(string[] args) { ListCreator.Register(SelfMadeList); var someIntegers = ListCreator.Create<int>(); foreach (var item in someIntegers) { Console.WriteLine("Some integer: " + item); } var someDoubles = ListCreator.Create<double>(); foreach (var item in someDoubles) { Console.WriteLine("Some doubles: " + item); } var someTimeSpans = ListCreator.Create<TimeSpan>(); foreach (var item in someTimeSpans) { Console.WriteLine("Some timespans: " + item); } Console.ReadKey(); } private static List<TimeSpan> SelfMadeList() { return Enumerable.Range(1, 20) .Select(Convert.ToDouble) .Select(val => val + 0.5) .Select(TimeSpan.FromHours) .ToList(); } }