1

I want to put a non generic class into a List with the type of a generic base class. However the code wont combile with the error that a conversion is not possible. I am pretty new to C# so I might just miss something very basic here or my approch to use generics that way is just no good idea? My code looks something like this:

public abstract class AbstractClass{
  public string foo;
}

public class A : AbstractClass{
  public int bar
}

public class B : AbstractClass{
  public int baz
}

public abstract class AbstractBehaviour<T> : MonoBehaviour where T : AbstractClass{
  public T data;
  public abstract string compute(T arg);
}

public class ABehaviour : AbstractBehaviour<A>{
  //some implementation of compute
}

public class BBehaviour : AbstractBehaviour<B>{
  //some implementation of compute
}

With this setup I would like to do something like this:

ABehaviour a = new ABehaviour();
BBehaviour b = new BBehaviour();
List<AbstractBehaviour<AbstractClass>> list = new List<AbstractBehaviour<AbstractClass>>();
list.Add(a);
list.Add(b);

Thank you very much.

Tim
  • 75
  • 5
  • 2
    `ABehaviour` and `BBehaviour` do not inherit from `AbstractClass`. – John Wu Jun 04 '20 at 21:59
  • Have you looked into interfaces? Not sure exactly what you are trying to do but it looks interface-y to me. – Jacob Huckins Jun 04 '20 at 22:04
  • You really don't want to use `MonoBehaviour` for everything. It's very heavyweight and a performance hog. – Retired Ninja Jun 04 '20 at 22:11
  • @JacobHuckins - I have tried to substitute the `AbstractClass` with an Interface to no avail. And as the abstract class really only needs to hold on to some variables which both super classes have i changed it back to an class. – Tim Jun 05 '20 at 06:54
  • @RetiredNinja The idea was to use the Behaviour classes as some sort of controller for the data classes (as in MVC). So they can handle stuff like adding an healthbar to themselfes or change to a different shader. From a performance point of view would it be better to handle this stuff in one behaviour class than seperate ones? – Tim Jun 05 '20 at 07:01

2 Answers2

1

When you are calling:

List<AbstractBehaviour<AbstractClass>> list = new List<AbstractBehaviour<AbstractClass>>();

Notice that your class AbstractBehaviour needs that T have to be an AbstractClass, not the type itself.

So you can do:

List<AbstractBehaviour<A>> list = new List<AbstractBehaviour<A>>();

Cause A implements the type AbstractClass, it's not the type itself.

Edit: To store on the list both AbstractBehaviours you need to find the "minimum common class" which in this case is the Monobehaviour, cause AbstractBehaviour inherits from Mono.

So if you make:

List<MonoBehaviour> list = new List<MonoBehaviour>();
list.Add(a);
list.Add(b);

It will compile, but then you have to check which type are you dealing inside the collections, doing casts like:

ABehaviour aBehaviour = (ABehaviour)list[0];
BBehaviour bBehaviour = list[1] as BBehaviour;
Lotan
  • 4,078
  • 1
  • 12
  • 30
  • Thank you for you answer. With your solution I would not be able to put `BBehaviour` in the list as well and that is basicly what i wanted to achieve with the whole generics thing. – Tim Jun 05 '20 at 06:46
  • @Latan As you stated your approach does indeed compile. It seems a bit 'dirty' to me though, seeing as I loose all type information for further use. – Tim Jun 05 '20 at 14:39
1

You can't because AbstractBehaviour<A> (or AbstractBehaviour<B>) is not AbstractBehaviour<AbstractClass>. If we take for example Compute method - for AbstractBehaviour<AbstractClass> would be absolutely valid to call it with parameter of type AbstractClass while it is definitely not valid to call AbstractBehaviour<A>.compute with this parameter.

Also please read about covariance and contravariance in C#(but it will not help with your Compute method)

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • [here](https://stackoverflow.com/questions/6508529/c-sharp-covariant-generic-parameter) is elaborated why classes are not covariant. Also a nice pointer is how to [create a variant interface in C#](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/creating-variant-generic-interfaces) – Tim Jun 05 '20 at 18:55