好。我会简短一点。为什么这不起作用?
//Find<T> returns the T object with a given name
//Not a true method, but that's simplier for the example.
Warrior conan = Find<Warrior> ("Conan");
//Debug.Log is just printing the results
Debug.Log (conan is Warrior); //True
Debug.Log (conan is Character); //True, Warrior extends Character
Character other = Find<Character> ("Conan"); // Null, Why ?
我认为通用的c#方法在IL中是非常不同的,这就是为什么它不起作用的原因。但它很烦人。我做错了吗?有没有办法绕过这个?
编辑:
事实上,我的方法有点不同。我正在使用MVC,我想找到与模型相对应的视图。
public ElementView<E> Find<E> (E model) {
ElementView<E>[] tab = gameBoardView.transform.GetComponentsInChildren<ElementView<E>> ();
foreach (ElementView<E> el in tab)
if (EqualityComparer<E>.Default.Equals(el.model, model))
return el;
return null;
}
我这样使用它:
ElementView<Warrior> w = Find<Warrior> (myCharacter); // good if my character is a warrior
ElementView<Character> c = Find<Character> (myCharacter); // null
答案 0 :(得分:2)
如评论中所述,如果您要研究泛型类型参数的差异,您可以自己回答这个问题。推荐阅读包括:
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的Wizards and warriors系列(此链接指向第1部分)
尽管如此,努力解决您的直接关注并可能提供一些实用,可操作的信息......
你的方法在这里打破:
ElementView<E>[] tab = gameBoardView.transform.GetComponentsInChildren<ElementView<E>> ();
具体来说,model
的类型为Warrior
,ElementView<Warrior>
搜索的集合中的GetComponentsInChildren<T>()
实例将被Find<Character>()
搜索。当您致电GetComponentsInChildren<Character>()
时,您会调用通用方法ElementView<Character>
,该方法会搜索ElementView<Warrior>
的实例。
由于ElementView<Character>
不是ElementView<Character>
- 也就是说,它不会继承该类型 - 它会从搜索中排除。搜索将返回{em>仅{/ 1}}的实例,这些实例将不包含相关模型的视图。 (如果Character
只是所有真实类型使用的基类,则返回的集合实际上可能是空的...只有在组件集合中有实际的ElementView<Character>
对象时,您才会得到任何对象通过该方法返回。)
您是否可以对此做任何事情取决于类型ElementView<T>
以及您是否能够在代码中引入接口类型来表示ElementView<T>
个对象。也就是说,GetComponentsInChildren<T>()
仅在以下情况下请求类型ElementView<Warrior>
的对象时才返回ElementView<Character>
类型的对象是合法的:
ElementView<T>
类型(例如IElementView<T>
)和T
可以声明为协变;也就是说,使用out
关键字,表示接口的所有成员只能返回类型为T
的对象,而不接受它们作为参数。如果这些都是真的,那么你可以声明适当的接口,确保ElementView<T>
实现该接口,然后类型为ElementView<Warrior>
的对象可以转换为接口类型{{1} }。由于接口类型参数为IElementView<Character>
,并且接口实现只能返回类型为Character
的对象,因此对象实际返回类型为Character
的对象的事实可以。 Warrior
(大概)是Warrior
,因此返回Character
会满足接口返回Warrior
值的声明。
如果您可以满足这些要求,那么Character
方法可能会返回GetComponentsInChildren<T>()
类型的数组,实际上可能包含您感兴趣的对象,实际上是IElementView<T>[]
类型{ {1}}继承ElementView<U>
(即U
将返回T
,其中查找GetComponentsInChildren<Character>()
的实例是有效的。
当然,您还需要更改使用这些类型的代码,包括IElementView<Character>[]
(取决于其实现)。这不是一种简单的“抛弃切换”类型的变化来支持泛型类型的变化。但假设您的类型与变体声明兼容,那么这是值得的。
我无法就如何进行这些更改提供任何具体建议,或者即使它们是可能的,因为您的问题不包括好Minimal, Complete, and Verifiable code example。如果您想进行这些更改,我建议您先研究差异,然后自行尝试更改代码。如果你之后仍然遇到麻烦,请发一个新问题,确保包含一个好的MCVE,清楚地显示你想要做的事情,并准确地解释你仍然遇到麻烦的事情。