3

I have a casting problem I am unable to solve :

in ClassA initialize function, I want to pass 'this' as parameter, but the compiler cannot cast from ClassA<T, U> to ClassA<ClassB<U>, U> knowing that they are the same (where T : ClassB<U>).

public class ClassA<T, U> : MonoBehaviour where T : ClassB<U>
{
    public void initialize()
    {
        T item =...
        item.Initialize(this); // Cannot implicitly convert from ClassA<T, U> to ClassA<ClassB<U>, U>.
    }
}

public class ClassB<T> : MonoBehaviour
{
    public virtual void Initialize(ClassA<ClassB<T>, T> mgr, T data)
    {
        ...
    }
}

Thanks.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Grit
  • 31
  • 1
  • 2
    Why do you think you can cast from `ClassA` to `ClassA, U>`? Generic classes are invariant. You can't cast a `List` to a `List`, for example. Same thing happens here. – Sweeper Jan 13 '20 at 11:26
  • A and B are not the same. You can cast from B to A, but not A to B. Suppose B is a box that can contain a max of 50 marbles. And A is a box that can contain max 100 marbles. You can always take B and put into A. But if you put A into B you are probably going to have a lot of marbles on the floor. – jdweng Jan 13 '20 at 11:27
  • Possible Duplicate: https://stackoverflow.com/a/1817341/5133585 – Sweeper Jan 13 '20 at 11:28
  • well,in the definition of ClassA, you have : "where T : ClassB" – Grit Jan 13 '20 at 11:28
  • @Grit that doesn't make any difference whatsoever to what `this` is; that's just a re-statement of `Elephant : Animal` in my answer – Marc Gravell Jan 13 '20 at 11:29
  • One possible option here might be to make `Initialize` itself generic; not pretty, though – Marc Gravell Jan 13 '20 at 11:30
  • I just don't get your point. In my understanding, T and ClassB are the same (where T : ClassB) – Grit Jan 13 '20 at 11:33
  • 1
    @Grit that doesn't mean "the same", though; it means that *any* `T` that is, or inherits from, `ClassB`, is allowed – Marc Gravell Jan 13 '20 at 11:35
  • ok, I get it. Is there a way to say "T is ClassB" then? And thanks everyone for your replies. – Grit Jan 13 '20 at 11:38

2 Answers2

10

Consider: Elephant : Animal; this does not mean that List<Elephant> : List<Animal>, and you cannot cast a List<Elephant> to a List<Animal> for many reasons (including: that would let you Add(monkey) to the List<Elephant>, after casting to List<Animal>, because Monkey : Animal). It is exactly the same here, conceptually.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
0

This does not work for classes. It only works if ClassB was an interface with an out type parameter as follows:

public interface IInterfaceB<out T>
{
   …
}

However, an out type parameter means that you can only use the type parameter T for return values in your IInterfaceB interface members, not for parameters.

Georg
  • 5,626
  • 1
  • 23
  • 44