2017-06-29 212 views
0

好的。我會簡短介紹一下。爲什麼這不起作用?爲什麼泛型方法不能用於繼承和接口?

//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 
+6

添加Find 的代碼將有所幫助。 –

+4

請顯示'Find'方法的來源。 – dasblinkenlight

+0

如何提出一個好問題:[問]以及如何提供良好的示例代碼:[mcve] – AndyJ

回答

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
埃裏克利珀的Wizards and warriors系列(此鏈接是第1部分)

也就是說,在努力解決您的直接關注,並可能提供一些實用的,可操作的信息......

你的方法打破了這裏:

ElementView<E>[] tab = gameBoardView.transform.GetComponentsInChildren<ElementView<E>>(); 

具體來說,model的類型是Warrior,這將有由GetComponentsInChildren<T>()被搜索的ElementView<Warrior>集合中的一個實例。當您撥打Find<Character>()時,您可以調用通用方法GetComponentsInChildren<Character>(),該方法將搜索ElementView<Character>的實例。

由於ElementView<Warrior>不是ElementView<Character> —即,它不繼承該類型—它被從搜索中排除。搜索將返回只有ElementView<Character>的實例,該實例不包括所討論模型的視圖。 (如果Character只是所有實際類型使用的基類,則返回的集合實際上可能爲空;只有在組件集合中存在實際的ElementView<Character>對象時,纔會收到該方法返回的任何對象。)

您是否可以對此做任何事情取決於類型ElementView<T>以及您是否能夠在代碼中引入接口類型來表示ElementView<T>對象。也就是說,這將是合法的,當你問ElementView<Character>類型的對象只有GetComponentsInChildren<T>()返回ElementView<Warrior>類型的對象:

  1. 您可以更改代碼返回接口類型,而不是ElementView<T>類型的集合(例如IElementView<T>)和
  2. 可以將接口的類​​型參數T聲明爲協變;即out關鍵字,表示接口的所有成員只有返回類型爲T的對象,並且不接受它們作爲參數。

如果這些事情是真實的,那麼你可以申報相應的接口,確保ElementView<T>實現該接口,然後ElementView<Warrior>類型的對象可以強制轉換爲接口類型IElementView<Character>。由於接口類型參數是Character,並且接口實現只能返回類型爲Character的對象,所以對象實際上返回Warrior類型的對象的事實就沒有問題。 Warrior(假定)是Character,因此返回Warrior滿足接口返回Character值的聲明。

如果你能滿足這些要求,則GetComponentsInChildren<T>()方法可以返回IElementView<T>[]類型的數組,這實際上可以包含您感興趣的對象,實際上是鍵入ElementView<U>其中U繼承T(即GetComponentsInChildren<Character>()將返回IElementView<Character>[],其中找到IElementView<Warrior>的實例是有效的)。

當然,您還需要更改使用這些類型的代碼,包括GetComponentsInChildren<T>()(取決於其實現方式)。這不是一個簡單的「拋開開關」類型的變化來支持泛型類型的變化。但假設您的類型與變體聲明兼容,這可能是一個值得的努力。

我不能提供任何具體建議,說明如何進行這些更改,或者甚至是可能的,因爲您的問題不包括好的Minimal, Complete, and Verifiable code example。如果您想進行這些更改,我建議您先研究差異,然後自行努力更改代碼。如果之後仍然有問題,請發佈一個新問題,確保包含一個很好的MCVE,清楚地表明您正在嘗試做什麼,並且準確解釋您仍然遇到的問題。