简体   繁体   中英

Can't use an instance variable of non-generic class inheriting from a generic class with specified type

I created classes like these:

abstract class AClass1<T>
{
    // some code here
}

class Class2 : AClass1<int>
{
    // some code here
}

class Class3 : AClass1<float>
{
    // some code here
}

class Class4<T> : AClass1<T>
{
    // some code here
}

so far it works. But in another class I'd like to have:

...
AClass1<T> variable;

and depending on specific needs set that variable to either:

variable = new Class2();

or

variable = new Class3();

or sometimes:

variable = new Class4<T>();

this produces a compile error with no possible cast or anything else I tried. At the moment I just changed all inheriting classes to generic like:

class Class2<T> : AClass1<T>
{
    // some code here
}

but it doesn't feel right, because there are no generic methods or anything there.

The question is what is the right way to do it, why, and why I can't do it using my original way?

By the way this is .net 2.0 as I'm doing it inside Unity3D.

To be more clear:

I have some specific cases eg for int type that I want to handle specifically, but there are other I'd like to have a generic class for. So I created some subclasses that specifcally handle some types and I have also a generic subclass that I use when there is no specific implementation for a type. When I create a specific class for a type it should not be generic as it handles only one type.

A Class2 object is not assignable to an AClass1<T> variable, because Class2 is not derived from AClass1<T> , but AClass1<int> . These are incompatible types and the compiler cannot cast between them. Hence the compile error.

Maybe you can introduce a non-generic base class for AClass1<T> ?

The compiler is trying to help you by ensuring you don't perform assignments that aren't guaranteed to work. This isn't legal:

void foo<T>() {
  ...
  if (typeof(T) == typeof(int)) {
    AClass1<T> variable = new Class2();
  }
  ...
}

And that's because Class2 is only compatible with AClass1<int> -- if we don't know what T is, we can't in general say it's compatible with AClass1<T> . In the code above, it's a certainty that the conversion is possible, but the compiler isn't sophisticated enough to determine this code is safe -- in general, without the if , it wouldn't be. Casting doesn't work either, because there is no conversion from Class2 to AClass1<T> for arbitrary T .

To make this work, you have to forego compile-time type checking and force a runtime conversion -- it's always legal to cast to and from Object at compile time:

    AClass1<T> variable = (AClass1<T>) (object) new Class2();

If you get it wrong, the code will fail at runtime with an InvalidCastException .

This approach is dubious because it raises the question of why you are using generics (a compile-time type feature) and then circumventing them in your actual code. Code like this has to be carefully reviewed to see if this is really the most appropriate solution. Possible alternatives are introducing a non-generic base class, using containment for the generic types, or simply not using generics (if you're really only using float and int , is a generic base class adding anything?)

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