Assign List to a generic list - c#

How would you assign a list to a generic list since they are not the same type.
If I have a generic list:
List<T> myList = new List<T>();
and I have another list
List<OtherType> otherList = new List<OtherType>();
After I fill otherList with values. What are ways I can assign otherList to the generic list? Preferably without using a foreach.

if they are the same type you can do a basic type conversion
if(typeof(T) == typeof(OtherType))
myList = otherList as List<T>;
But that would make no sense, so I'd imagine you need some kind of conversion, problem is we need to specify that T is assignable from your base class
public static class StaticFoo
{
public static List<T> Foo<T>() where T : class
{
List<MyOtherClass> returnList = new List<MyOtherClass>() { new MyOtherClass() };
if(typeof(T).IsAssignableFrom(typeof(MyOtherClass)))
return returnList.Select(x => x as T).ToList();
throw new Exception($"Cannot convert {typeof(T)} to MyOtherClass");
}
}
public class MyClass { }
public class MyOtherClass : MyClass { }
The above code will work if you call it with T = MyClass or any other class that myOtherClass can be cast to. Alternatively you might want a concrete conversion method for a set of predefined types, it's kind of hacky but you could do something like this
public static class StaticFoo
{
public static List<T> Foo<T>() where T : class
{
List<MyOtherClass> returnList = new List<MyOtherClass>() { new MyOtherClass() };
return returnList.Select(x => x.Convert(typeof(T)) as T).ToList();
}
}
public class MyOtherClass {
public object Convert(Type type) {
if (type == typeof(string)) //more if statements for more types
return this.ToString(); //just an example
throw new NotImplementedException($"No cast available for type {type}");
}
}
Some context for the relationship between the generic type and your concrete class would be helpful
edit:
some advice that ignores your actual question. Most likely, you want to create an interface and return a list of that interface (I'm assuming that will match your use case more closely). Alternatively just change the signature to return List< object> - then you can do
return otherList.ToList<object>();

List<T> is invariant, so you can only assign lists of the same type. The closest you can come is creating a new list with the same items.
List<T> list = otherList.Select( x => (T)x ).ToList();

Related

Is it possible to extend List<T> but only for T = exact type?

I'm experimenting with extending classes and managed to extend List<T> for fun like so:
public static void SomeCustomSort<T>(this List<T> list, string item)
{
if (typeof(T) != typeof(string) || list.Count == 0)
return;
// doStuff();
}
I wondered if there was a smarter way to extend List<T> only for List<string> so that my extension method is not listed or accessable for any other type T
Just make your method non-generic:
public static void SomeCustomSort(this List<string> list, string item)
and specify exact type it should work with
NOTE: With void methods even if you want to restrict extension method parameter to some set of types (e.g. all implementors of some interface or some non-sealed class with classes derived from it) I would not recommend using generic method with parameter constraint:
public static void SomeCustomSort<T>(this List<T> animals)
where T: IAnimal
Why? Because it overcomplicates your code. Non-generic method is more simple to understand than generic method. Generic method without constraint is more simple to understand than generic method with constraint. You should start from the simplest solution which is easy to understand. What sounds more natural to you?
"It sorts list of animals"
"It sorts list of items of any type"
"It sorts list of items of any type which is animal"
When to use generic type constraint? When you return items from your method and you don't want to lose information about the exact type of list items. Consider method which returns animals by some weight filter
public static IEnumerable<IAnimal> WhereWeightBelow(this List<IAnimal> animals, int weight)
If you'll pass list of dogs to this method, you will lose intellisense for all dog-specific information in the method output.
dogs.WhereWeightBelow(10).Where(d => d. /* oops only IAnimal members here */)
Returning generic type will preserve all dog info for you.
Another alternative not yet mentioned:
public static void SomeCustomSort<T>(this List<T> list, string item)
where T: YourSpecificType
This allows you to specify more than just one type, for example:
public static void SomeCustomSort<T>(this List<T> list, string item)
where T: ISortable, ICustomInterface
Just specify T instead of making it a generic method.
public static void SomeCustomSort(this List<string> list, string item)
Just define exactly string type on your extension method
public static void SomeCustomSort(this List<string> list, string item)
{
// doStuff();
}
You can also use a constraint like this (in this example T would have to be of type Project):
public static void SomeCustomSort<T>(this List<T> list, string item)
where T : Project
{
}
I would show you in the following example how you can easily expand a generic list.
I expanded the list to return random data from the list itself.
We have a class for example:
public class ExampleClass
{
public string Name { get; set; }
}
We have now made a list of these classes in some method:
var exampleList = new List<ExampleClass>()
{
new ExampleClass()
{
Name = "Class1"
},
new ExampleClass()
{
Name = "Class2"
},
new ExampleClass()
{
Name = "Class3"
}
};
var randomList = exampleList.Random(2);
The following is a simple implementation of returning random objects from a list
public static class ListExtensions
{
public static IList<T> Random<T>(this IList<T> list, int numberOfResult) where T : class
{
if (list == null) throw new ArgumentNullException(nameof(list));
if (numberOfResult <= 0 || numberOfResult > list.Count) throw new ArgumentOutOfRangeException(nameof(numberOfResult));
var random = new Random();
var randomList = new List<T>();
var randomNumbers = new List<int>();
while (randomList.Count < numberOfResult)
{
var index = random.Next(list.Count);
if (randomNumbers.IndexOf(index) < 0)
{
randomNumbers.Add(index);
randomList.Add(list[index]);
}
}
return randomList;
}
}

Get type of elements in a List derived from List<T> in C#

Lets say that I have classes which derive from List<T>:
public class StringList : List<String> {}
public class NameList : StringList {}
public class IntList : List<int> {}
Now I have a generic method which expects type List<T>:
public static Method<T>() { ... }
How can I determine the type of elements contained in a list in this method, i.e. how to get the generic argument type in a derived class?
For base class I can call typeof(T>.GetGenericArguments(), but for derived class it returns zero size.
PS: In my concrete situation the type which method expects is not exactly List<T>, but IList.
You can write the method like this:
public static void Method<T>(List<T> thing) (or IList<T>)
{
//Here, `T` is the type of the elements in the list
}
Of if you need a reflection-based check:
public static void Method(Type myType)
{
var thing = myType.GetInterfaces()
.Where(i => i.IsGenericType)
.Where(i => i.GetGenericTypeDefinition() == typeof(IList<>))
.FirstOrDefault()
.GetGenericArguments()[0];
}
Note that you'll need appropriate sanity checks here (rather than FirstOrDefault() and 0 indexing)
If you want both the type of the list and the element type of the list at compile time, your Method must have two generic definitions like this:
public static void Method<T, E>(T list) where T : List<E>
{
// example1
// T is List<int> and E is int
// example2
// T is NameList and E is String
}
Method<List<int>, int>(new List<int>()); //example1
Method<NameList, string>(new NameList()); //example2

C# generic method can't create List<T>

I have one Interface and two classes.
public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }
I have a generic method,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
...
}
which should return a object-list based on data in DataTable. So, I create a list in this method which I want to return at the end. I thought I could do the following,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
List<T> myList = new List<T>;
// Now I thought I could easily add Objects based on T because,
// both classes implement the interface
if (typeof(T) == typeof(B))
{
myList.Add(new B());
}
else
{
myList.Add(new A());
}
return myList;
}
But the compiler tells me that "Argument type A (B) is not assigneable"! Why is it not assignable?
Ok, alternatively can I do the following,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
List<IMyInterface> myList = new List<IMyInterface>;
// Now I can assign the Object's :)
if (typeof(T) == typeof(B))
{
myList.Add(new B());
}
else
{
myList.Add(new A());
}
return myList as List<T>;
}
The compiler didn't complain but the result of the return clause is always null. For sure there are values in myList. The cast seems to fail. Someone please help me to solve this problem more elegantly.
One way is to add new() constraint. Limitation is that you need a public parameterless constructor for the type argument T.
private static List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
List<T> myList = new List<T>();
T instance = new T();
//access anything defined in `IMyInterface` here
myList.Add(instance);
return myList;
}
I don't understand what you're trying to do here. Why do you even need generics?
You were going the right way initially, deriving your types from the same interface, so make use of it. Declare your list List<IMyInterface> and simply add your objects as they are.
If later you actually need a physical representation of an enumerable with concrete A or B types, you have OfType<>() and Cast<>() for it, though it shows your polymorphism was done wrong in the first place.
Add a new constraint
private List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
return new List<T>(){ new T() };
}
You should cast object, before add it to List:
private static List<T> GetList<T>(DataTable table) where T : class, MyInterface
{
List<T> myList = new List<T>();
//Now i thought i can easily add Objects based on T, because both classes
//implement the interface
if (typeof (T) == typeof (B))
{
// use of 'as' operator
myList.Add(new B() as T);
}
else
{
myList.Add(new A() as T);
}
return myList;
}
But anyway I am not getting a point, what your are trying to achieve.
Also myList as List<T> will surely result as null, since you cannot cast generic collection with as operator as List<T> is not declared as Covariant. You should explicitly call .Cast<T>() method to create new collection.
I'm guessing you actually want to do something like,
public IList<T> GetList<T>(
DataTable table,
Func<DataRow, T> extractor)
{
var result = new T[table.Rows.Count];
for (var i = 0; i < table.Rows.Count; i++)
{
result[i] = extractor(table.Rows[i]);
}
return result;
}
extractor being the delegate for converting a DataRow to T.
this would work more simply than you might expect,
// referencing System.Data.DataSetExtensions
var list = GetList(
data,
row => new A
{
Id = row.Field<int>("id"),
...
});
list would be an IList<A> among other types.
Try this:
private List<T> GetList<T>(DataTable table) where T : class, IMyInterface {
List<T> myList = new List<T>();
if (typeof(T) == typeof(B)) {
myList.Add((T)new B());
}
else {
myList.Add((T)new A());
}
return myList
}
Right only for class A and B
static List<T> GetList<T>(DataTable table) where T : class, IMyInterface
{
List<T> myList = new List<T>();
IMyInterface obj;
if (typeof(T) == typeof(B))
{
obj = new B();
}
else
{
obj = new A();
}
myList.Add((T)obj);
return myList;
}

Casting List<object> to List<T> at runtime

I 'm trying to build a DI container and I 've stumbled on to the following problem: I have a method that retrieves a list of registered instances for a given type and I want to use that to inject IEnumerable<T> properties in a given object. An example of what I am trying to achieve would be the following:
class A { public IList<IExample> Objects { get; set; } }
class B: IExample {}
class C: IExample {}
Container.Register<IExample>(new B());
Container.Register<IExample>(new C());
var obj = new A();
Container.Inject(A);
Debug.Assert(A.Objects != null && A.Objects.Count == 2);
My Retrieve method returns an IList<object>, mainly because I have no type information at that moment, so I am attempting to convert that list into a List<T> at injection time. Here is a succint form of the methods doing the work:
public virtual IList<object> Retrieve(Type type)
{
var instances = Registry[type];
foreach(var instance in instances)
Inject(type, instance); // omitted
return instances;
}
public virtual void Inject<T>(T instance)
{
var properties = typeof (T).GetProperties();
foreach (var propertyInfo in properties)
{
var propertyType = propertyInfo.PropertyType;
if (!IsIEnumerable(propertyType)) continue;
var genericType = propertyType.GetGenericArguments()[0];
propertyInfo.SetValue(instance,
GetListType(genericType, Retrieve(genericType)), null);
}
}
protected virtual object GetListType(Type type, IEnumerable<object> items)
{
return items.Select(item => Convert.ChangeType(item, type)).ToList();
}
The code returns the error: System.InvalidCastException : Object must implement IConvertible. Sadly, I don't know how to proceed from here. Perhaps I am doing this all wrong. I 've thought of using generics or injecting multiple properties by hand, but I'd really like to not have to do that.
Thanks in advance for any help or ideas.
You could create a generic list like this:
public virtual IList Retrieve(Type type)
{
// ...
listType = typeof(List<>).MakeGenericType(new Type[] { type });
IList list = (IList)Activator.CreateInstance(listType);
// ...
return list
}
this list can be casted to IList<T>, because it is one.
You could consider to use IEnumerable and Cast<T>, but then you don't have an instance of a list. I don'^t know how important it is to have one.

Having trouble with Generics in this .NET code

i'm trying to make a mixed collection of Types. I know the types at the start.. but I can't seem to figure out the syntax to make the collection, etc.
eg.
....
// I leave the typo there, for embarrassment :(
Initialize(new []{ typeof(Cat), typeof(Dog), typeof(JohnSkeet) });
...
public Foo Initialize(IEnumerable<Type> types)
{
// for each type, set up the inmemory storage.
foreach(var type in types)
{
// ????
// Create an empty list, which will only contain this 'type'
// I'm guessing, an IDictionary<type, ICollection<type>>().. thingy ?
}
}
public ICollection<Type> SomeTypeData(Type type)
{
// Return the collection, for this type.
}
Does this mane sense? Is this possible?
Okay, now that I think I know what you want, it would look something like this:
// This can't really be *properly* statically typed
private readonly Dictionary<Type, object> typeMap = new
Dictionary<Type, object>();
public Foo Initialize(IEnumerable<Type> types)
{
Type genericListType = typeof(List<>);
foreach(var type in types)
{
// MakeGenericType is really badly named
Type constructedListType = genericListType.MakeGenericType(type);
typeMap[type] = Activator.CreateInstance(constructedListType);
}
}
// We can't express this particularly safely either,
// although we *could* return the non-generic IList
public object SomeTypeData(Type type)
{
return typeMap[type];
}
// This *is* statically typed, although we need to cast inside
public IList<T> SomeTypeData<T>()
{
return (IList<T>) typeMap[typeof(T)];
}
See this blog post for a similar example.
Note that basically you're trying to represent something which generics simply can't handle, in terms of the internal dictionary type... and the first form of SomeTypeData can't be statically typed either... because that means knowing the type at compile time when we'll only actually be given it at execution time.
It looks to me like you're trying to create some kind of instance repository; a class that stores a list of instances of a given type.
Here's an example implementation. I've included both a generic and non-generic version of the SomeTypeData method:
public class InstanceRepository
{
private IDictionary<Type, ICollection> _Instances = new Dictionary<Type, ICollection>();
public ICollection SomeTypeData(Type type)
{
ICollection instanceList;
if (!_Instances.TryGetValue(type, out instanceList))
{
// this type does not exist in our dictionary, so let's create a new empty list
// we could do this:
//instanceList = new List<object>();
// but let's use reflection to make a more type-specific List<T> instance:
instanceList = (ICollection)Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
// now add it to the dictionary
_Instances.Add(type, instanceList);
}
// Return the collection, for this type.
return instanceList;
}
public IList<T> SomeTypeData<T>()
{
Type type = typeof(T);
ICollection instanceList;
if (!_Instances.TryGetValue(typeof(T), out instanceList))
{
instanceList = new List<T>();
_Instances.Add(type, instanceList);
}
// here we are assuming that all of the lists in our dictionary implement IList<T>.
// This is a pretty safe assumption, since the dictionary is private and we know that
// this class always creates List<T> objects to put into the dictionary.
return (IList<T>)instanceList;
}
}
Below is a usage example:
Generic:
InstanceRepository repository = new InstanceRepository();
var listOfCats = repository.SomeTypeData<Cat>();
listOfCats.Add(new Cat());
Cat firstCat = listOfCats[0];
Console.WriteLine(listOfCats.GetType().FullName);
Non-Generic:
InstanceRepository repository = new InstanceRepository();
var listOfCats = (IList<Cat>)repository.SomeTypeData(typeof(Cat));
listOfCats.Add(new Cat());
Cat firstCat = listOfCats[0];
Console.WriteLine(listOfCats.GetType().FullName);
I guess you want something like
_dict[typeof(Cat)]=new List<Cat>();
_dict[typeof(Dog)]=new List<Dog>();
only programatically based on given types?
Something like this should work:
public void Initialize(IEnumerable<Type> types)
{
foreach(var type in types)
{
var list = Activator.CreateInstance(Type.GetType("System.Collections.Generic.List`1").MakeGenericType(type));
_cache[type] = list;
}
}
public ICollection<T> Get<T>()
{
object list;
if (_cache.TryGetValue(typeof(T), out list)
{
return list as ICollection<T>;
}
else
{
...
}
}
var cats = Get<Cat>();
I'm not sure I fully understand you're question, but if you already have an IEnumerable<Type> which contains an enumeration of Type objects, then why not just use that to initialize some type of Collection (such as List<Type>)?
public ICollection<Type> Initialize(IEnumerable<Type> types)
{
ICollection<Type> collection = new List<Type>(types);
return collection;
}

Categories