2016-08-31 179 views
1

我有一些類如下:隱泛型類型轉換不匹配重載方法簽名

public class RowBase { } 

public class SpecificRow : RowBase { } 

public class RowListItem<TRow> where TRow : RowBase { } 

public class SpecificRowListItem : RowListItem<SpecificRow> { } 

而且有些方法如下:

public string GetName<TRow>(RowBase row) where TRow : RowBase { } 

public string GetName<TRow>(RowListItem<TRow> item) where TRow : RowBase { } 

我遇到的問題是,一個子類的RowListItem未能匹配第二個重載的簽名。這裏是一個例子:

var foo = new SpecificRow(); 
var bar = new SpecificRowListItem(); 
var baz = new RowListItem<SpecificRow>(); 
string name; 
name = GetName(foo); // invokes first overload as expected 
name = GetName(baz); // invokes second overload as expected 
name = GetName(bar); // does not compile 
name = GetName((RowListItem<SpecificRow>)bar); // this alternative invokes the second overload 
name = GetName<SpecificRow>(bar); // this alternative also invokes the second overload 

編譯器誤差是

錯誤CS0311類型「ConsoleApplication1.SpecificRowListItem」不能在通用類型或方法「Program.GetName被用作類型參數「特羅」(特羅)」。沒有從「ConsoleApplication1.SpecificRowListItem」到「ConsoleApplication1.RowBase」的隱式引用轉換。

由於SpecificRowListItemRowListItem<TRow>TRow符合where TRow : RowBase約束一個子類,我希望編譯器將能夠告訴它應該與第二過載時提供的參數作爲類的一個實例。但是,編譯器錯誤的文本表明它試圖匹配第一個過載(GetName(TRow))。我想明白爲什麼會這樣,並且如果有任何事情可以解決問題,而不是兩種可行的方案。我試過這個:

public string GetName<TItem, TRow>(TItem item) 
    where TItem : RowListItem<TRow> 
    where TRow : RowBase 

除了醜陋,它給了我同樣的問題(似乎匹配第一次重載)。

回答

1

RowListItem<SpecificRow>RowListItem<BaseRow>沒有關係,它不是從它派生出來的。

檢查泛型中的協方差。這個答案可能會幫助您:"out T" vs. "T" in Generics

工作例如:

using System; 

namespace CoVariance 
{ 
    public class RowBase { } 

    public class SpecificRow : RowBase { } 

    public class RowListItem<TRow> : IInputSave<TRow> where TRow : RowBase { } 

    public class SpecificRowListItem : RowListItem<SpecificRow> { } 

    internal interface IInputSave<out TRow> 
     where TRow : RowBase 
    { 
    } 

    class Program 
    { 
     public static void Main(string[] args){ 

      var foo = new SpecificRow(); 
      var bar = new SpecificRowListItem(); 
      var baz = new RowListItem<SpecificRow>(); 
      string name; 

      name = GetName(foo); 
      Console.WriteLine(name); //oink 
      name = GetName(baz); 
      Console.WriteLine(name); //nested oink 
      name = GetName(bar); 
      Console.WriteLine(name); //nested oink 
      name = GetName((RowListItem<SpecificRow>)bar); 
      Console.WriteLine(name); //nested oink 
      //name = GetName<SpecificRow>(bar); 

      Console.ReadKey(); 
     } 

     public static string GetName(RowBase row) 
     { 
      return "oink"; 
     } 

     public static string GetName(IInputSave<RowBase> item) 
     { 
      return "nested oink"; 
     } 
    } 
} 
+0

謝謝,但我不會跟着你。根據我的理解,你的答案'GetName((RowListItem )bar)'也應該失敗,因爲它不是從'RowListItem '派生的。但是,它成功了,因爲where TRow:BaseRow約束條件與任何從BaseRow繼承的TRow匹配。我的問題是,是否有一個原因,即使第一個從第二個繼承?編譯器不能隱式地從'SpecificRowListItem'轉換爲'RowListItem '? –

+0

我基於您的示例在c#中利用協變量來添加一個工作示例給我的答案。 但我不能夠正確地解釋給你,因爲我不完全理解自己由xD 但有很多閱讀有關在互聯網上的東西:d – keydon

+0

我很高興你不明白它須─ - 讓我覺得自己少了一個doofus ;-) [This link](http://stackoverflow.com/a/9381751/4062628)也很有趣。 –