2016-08-31 8 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は、2番目のオーバーロードのシグネチャと一致しません。ここでの例は以下のとおりです。

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 

コンパイラエラーが型「ConsoleApplication1.SpecificRowListItemは」ジェネリック型またはメソッド「Program.GetName(中型のパラメータ「トロウ」として使用することはできません

エラーCS0311ですTRow) 'と表示されます。 'ConsoleApplication1.SpecificRowListItem'から 'ConsoleApplication1.RowBase'への暗黙的な参照変換はありません。 SpecificRowListItemので

where TRow : RowBase制約を満たしTRowRowListItem<TRow>のサブクラスである、私は、コンパイラは、そのクラスのインスタンスとしてパラメータを提供する際、第2の過負荷と一致する必要があることを伝えることができるだろうことを期待します。ただし、コンパイラエラーのテキストは、最初のオーバーロード(GetName(TRow))と一致しようとしていることを示しています。私はその理由を理解したいと思っています。何かがあれば、問題の解決に2つの選択肢以外の解決方法があります。私はこれを試みた:

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#の共分散を活用するための例に基づいて私の答えに実例を加えました。 私はそれを自分自身で完全に理解していないので、私はあなたにそれを正しく説明することができませんが、インターネット上でそのことについて読むことはたくさんあります: – keydon

+0

私はあなたがそれを理解していないことをうれしく思っています - 私はdoofusのように感じるようになりました;-) [This link](http://stackoverflow.com/a/9381751/4062628)も面白かったです。 –

関連する問題