As noted in the comments, you could probably answer this question yourself, if you would study variance in generic type parameters. Recommended reading includes:
In C#, why can't a List object be stored in a List variable
C# variance problem: Assigning List as List
Contravariance explained
Difference between Covariance & Contra-variance
Eric Lippert's Wizards and warriors series (this link is to part 1)
That said, in an effort to address your immediate concern and to possibly provide some practical, actionable information…
Your method breaks here:
ElementView<E>[] tab = gameBoardView.transform.GetComponentsInChildren<ElementView<E>> ();
Specifically, the type of the model
is Warrior
, which will have an instance of ElementView<Warrior>
in the collection being searched by GetComponentsInChildren<T>()
. When you call Find<Character>()
, you call the generic method GetComponentsInChildren<Character>()
, which will search for instances of ElementView<Character>
.
Since ElementView<Warrior>
is not an ElementView<Character>
— that is, it doesn't inherit that type — it is excluded from the search. The search would return only instances of ElementView<Character>
, which will not include the view for the model in question. (The returned collection may in fact be empty, if Character
is simply the base class used by all of the real types…only if there are actual ElementView<Character>
objects in the components collection would you even get any objects returned by the method.)
Whether you can do anything about this depends on the type ElementView<T>
and whether you are able to introduce an interface type into your code to represent ElementView<T>
objects. That is, it would be legal for GetComponentsInChildren<T>()
to return objects of type ElementView<Warrior>
when you ask for objects of type ElementView<Character>
only if:
- You can change the code to return a collection of interface types instead of
ElementView<T>
types (e.g. IElementView<T>
), and
- The interface's type parameter
T
can be declared as covariant; that is, with the out
keyword, indicating that all members of the interface only ever return objects of type T
, and not accept them as parameters.
If those things were true, then you could declare the appropriate interface, make sure that ElementView<T>
implements that interface, and then objects of type ElementView<Warrior>
could be cast to the interface type IElementView<Character>
. Since the interface type parameter would be Character
, and the interface implementation could only return objects of type Character
, the fact that the object is actually returning an object of type Warrior
would be fine. Warrior
is (presumably) a Character
, and so returning a Warrior
satisfies the interface's declaration of returning Character
values.
If you could meet those requirements, then the GetComponentsInChildren<T>()
method could return an array of type IElementView<T>[]
, which could in fact contain your object of interest that is actually type ElementView<U>
where U
inherits T
(i.e. GetComponentsInChildren<Character>()
would return IElementView<Character>[]
, in which it would be valid to find an instance of IElementView<Warrior>
).
Of course, you'd also need to change the code that uses these types, including GetComponentsInChildren<T>()
(depending on its implementation). It's not a simple "throw the switch" kind of change to support variance in your generic types. But assuming your types are compatible with variant declarations, it can be a worthwhile effort.
I can't provide any specific advice on how exactly those changes would be made, or even if they are possible, since your question does not include a good Minimal, Complete, and Verifiable code example. If you want to make these changes, I recommend you study variance first, then make an effort on your own to change the code. If you still have trouble after that, post a new question, being sure to include a good MCVE showing clearly what you're trying to do, and explain precisely what it is you're still having trouble with.