简体   繁体   中英

How do I use polymorphism with a generic type who's type argument is a child of the type parameter constraint in c#?

I have a genericType whos type constraint is a base class. When I try to assign a value to this type, using a subclass of the type constraint, it doesn't work.

I understand that the reasoning for this is because compiler sees these as two completely different types.

Is there a work around for this? The only thing I can think of is to create an interface which the Generic Class implements an exposes the type through by whatever means. In the example below I could just make the barInstance the implementation of a property defined in the interface. But this creates some boiler plate. Cheers!

public class Bar { }

public class SubclassOfBar : Bar { }

public class GenericClass<T> where T : Bar { 
    public T barInstance;
}

public class Example
{
    public void Test()
    {
        GenericClass<Bar> fooBar = new GenericClass<SubclassOfBar>(); // Does not compile
    }
}

Work Around with interface:

public class Bar { }

public class SubclassOfBar : Bar { }

public class GenericClass<T> : IHaveBar where T : Bar
{
    public T barInstance;
    public Bar BarInstance => barInstance;
}

public class Example1
{
    public void Test()
    {
        IHaveBar fooBar = new GenericClass<SubclassOfBar>(); // Does Compile
    }

I understand what you're trying to do, but I do not understand why. If you want your variable fooBar.BarInstance to only have reference of the barInstance properties on not the derived instance, there are a few ways. I'll throw down the obvious ones as well, just incase :)

  1. Simply change the generic types to Bar.

     //Set both to the derived type. GenericClass<Bar> fooBar = new GenericClass<Bar>();
  2. Change both to the derived type and perform a cast:

     public void Test() { GenericClass<SubclassOfBar> fooBar = new GenericClass<SubclassOfBar>(); var instance = (Bar)fooBar.barInstance; }
  3. You could also go with your solution, but there is no need for an interface.

     public class Bar { } public class SubclassOfBar : Bar { } public class GenericClass<T> where T : Bar { private T barInstance; public Bar BarInstance => barInstance; } public class Example { public void Test() { var fooBar = new GenericClass<SubclassOfBar>(); var instance = fooBar.BarInstance; } }
  4. If you would like to remove the "boiler plate" code from the example above, you could put it all in an abstract class. (This assumes you are going to have more than one of these generic classes).

     public class Bar { } public class SubclassOfBar : Bar { } public abstract class AbstractGenericClass<T> where T : Bar { private T barInstance; public Bar BarInstance => barInstance; } public class GenericClass<T> : AbstractGenericClass<T> where T : Bar { } public class Example { public void Test() { var fooBar = new GenericClass<SubclassOfBar>(); var instance = fooBar.BarInstance; } }

Let me know if I need to clarify anything!

Happy coding!

If you want to do some generic stuff in the Test method, you could pass in the type in the method as well. The code would become like this.

public void Test<T>() where T : Bar
{
    GenericClass<T> fooBar = new GenericClass<T>();
}

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