简体   繁体   中英

Cast Generic Object with getting type from Reflection

I'm trying to cast an object in a generic object where I need to change the type dynamically.

Dog<T> inherits Animal , class " T " must inherit from EntityBase . For example, Chihuahua inherits EntityBase .

for (int i = 0; i < list.Count(); i++) {
    if (list?.ElementAt(i)?.GetType().GetTypeInfo().BaseType == typeof(Animal))
    {
        var type = list.ElementAt(i).GetType();
        // is wrong, must use a class no a type
        // var animal = list.ElementAt(i) as GenericObject<Dog<type>> 
        // Correct syntax but cast results null
        var animal = list.ElementAt(i) as GenericObject<Dog<EntityBase>> 
        // animal is null
        DoStuff(animal);
    }

If I use this code, it works:

if (list?.ElementAt(i)?.GetType() == typeof(Dog<Chihuahua>))
{   
    DoStuff(list.ElementAt(i) as Dog<Chihuahua>);
}

I want to do this as generically as possible, thanks a lot!

I will share the project I'm doing when I finish!

The ability to have a single list hold different kinds of related types is called covariance (contravariance is also related). This is achieved in .NET with the out and in keywoards respectively. With .NET 4.5, covariance is built into IEnumerable<T> . IEnumerable<T> is implemented by IList<T> , which is implemented by List<T> .

If you have a list of Animal s, you can add any subtype of Animal to the list. However, when you get that animal out, in code, you get a variable of type Animal that points to your subtype of Animal . So it looks like you only have an Animal but it's really the subtype. You could try to manually cast everything as you suggested.

There is another workaround (.NET 4.5), you can use the dynamic keyword to have the type be determined at runtime. Then overload the DoStuff method, it should behave the way you want.

public class Animal
{
    public string Name;
    public Animal() { Name = "Animal"; }
}

public class Dog:Animal
{
    public Dog() { Name = "Dog"; }
}

[TestMethod]
public void Test()
{
    var list = new List<Animal>();
    list.Add(new Dog());
    list.Add(new Animal());
    foreach(dynamic a in list)
    {
        DoStuff(a);
    }
}

public void DoStuff(Animal animal)
{
    Console.WriteLine("{0} is wild", animal.Name);
}

public void DoStuff(Dog dog)
{
    Console.WriteLine("{0} is not wild", dog.Name);
}

This is the output

Test Name:  Test
Test Outcome:   Passed
Result StandardOutput:  
Dog is not wild
Animal is wild

Covariance and contravariance is a complex topic. Check out these other posts. Difference between Covariance & Contra-variance Difference between covariance and upcasting

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM