4

私は次のサンプルコードを持っています(C#3.5の学習目的にのみ使用されます)。

IEnumerableとsort関数を受け付けるSort関数を呼び出しています。ラムダ式を使用してそれを呼び出すと(ケースA)、コンパイラは戻り型TResultを派生させることができますが、func SortIntを渡すと(ケースB)、コンパイラはエラーをスローします。

2番目のケースでコンパイラがなぜTResultを導出できないのか理解できません。私はまったく同じ情報を渡しているようです。それとも正確ではないですか?

助けてください !

int[] intArray = { 1, 3, 2, 5, 1 };

IEnumerable<int> intArray2 = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

IEnumerable<int> nextIntArray = Sort(intArray, SortInt); // <= CASE B - Compile Error: Cannot Infer Type !

public static IEnumerable<TResult> Sort<T, TResult>(IEnumerable<T> toBeSorted,    
                              Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
{
    return sortFunc(toBeSorted);
}

public static IEnumerable<int> SortInt(IEnumerable<int> array)
{
    return array.OrderByDescending(x => x);
}


  • インド人のようなあなたの名前はインド人です - Anirudha Gupta

4 답변


6

2番目の例では、コンパイラがSortIntに対してオーバーロード解決を実行できないため、推論が失敗したように見えます。

これはより徹底的な説明として役に立つかもしれません:

http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx


  • その記事は今やいくぶん古くなっています。その記事からのフィードバックに基づいて、このような状況では型推論アルゴリズムを多少改善しました。 - Eric Lippert
  • そうは言っても、はい、これはまだ我々がこの場合過負荷解決をすることができない方法の例です。 - Eric Lippert
  • @ロバート、ありがとう!その記事は正確にこの点を扱った! - Preets
  • @Eric、その記事をありがとう!改善点を説明する新しい記事を書いたことがありますか。それは素晴らしいことです! THX ! - Preets
  • わかった、見つけたblogs.msdn.com/ericlippert/archive/tags/Type+Inference/…! - Preets

5

型推論がメソッドグループの変換にはうまくいかないのは厄介だと思います。グループ内に適用可能なメソッドが1つしかないという一般的なケースでは、C#コンパイラをより賢くしたいと思います。ただし、複雑な状況では、さまざまな型が推論される原因となる、複数の適用可能なオーバーロードが発生する可能性があります。

オプション:

  • 表示されているように、ラムダ式からメソッドを呼び出します。
  • 推論に頼らずに型引数を明示的に指定する
  • メソッドグループを関連する特定のタイプにキャストします(2番目のオプションより悪い)
  • 別のローカル変数を使用してその型を明示的に指定する

基本的に私は最初の2つの選択肢のどちらかに固執するでしょう、それらが両方ともそうであるように迷惑です。最初のオプションでは間接的なレベルが増えるため、パフォーマンスがわずかに低下しますが、通常はそれほど重要ではありません。


  • ご説明ありがとうございます。型推論はメソッドグループでは機能しないことがわかりました。 '理解する理由私にとっては最も簡単な作業ではありませんが。 - Preets

3

IEnumerable<int> intArray = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

このステートメントでは、x => SortInt(x)は次のようにデリゲート表現です。

delegate(IEnumerable<int> x){
    return SortInt(x);
}

技術的には、ステートメントのどこかにSortIntへの参照を渡していません。

Func、IEnumerable>はデリゲート型です。つまり、関数へのポインタは必要ですが、関数は必要ありません。他にSortIntがメソッドです。

さらに深く掘り下げてみると、x => SortInt(x)の実際のコンパイル時表現は次のようになります。

private static IEnumerable<int> __XYZ(IEnumerable<int> x){
   return SortInt(x);
}

private delegate IEnumerable<int> __XYZHANDLER(IEnumerable<int> x);

そしてあなたの1行目は

IEnumerable<int> intArray = Sort(intArray, new __XYZHANDLER(__XYZ) );

今あなたの2行目を見て、SortIntは何もない、そのメソッド名です、それは任意の型やインスタンスではありません。メソッドパラメータが何かを持てるのは、何らかの型のインスタンスだけです。 new Delegateはメソッドポインタのインスタンスであり、メソッドではありません。

x => SortInt(x)は上記で説明したすべての短縮形です。lamdaは通常、匿名デリゲートを書くより小さな形式です。コンパイラはx => SortInt(x)に対してSortIntを推論しません。


0

あなたのコードはそれが機能するのを妨げていたいくつかの問題を抱えていました。

まず第一に、あなたのタイプはすべて一致しませんでした。 int []をIEnumerableとして渡していましたが、.AsEnumerable()を呼び出さずにそれを実行することはできません。

第2に、TとTResultは、使い方は同じですが(int)、コンパイラと同じではありませんが、整数の配列を渡し、結果の種類が何であるかを言わずにIEnumerableを期待しています。それで、あなたはあなたのバージョンと一緒にTResultの型を渡す必要があるでしょう(Sort(intArray.AsEnumerable()、SortInt)のように)、しかしあなたはちょうど同じ型Tを注文されるのであなたはTResultを必要としません

だから、私はTResultを取り除き、タイプを修正しました:

void Main() 
{
  var intArray = new [] { 1, 3, 2, 5, 1 };
  var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
  var nextInts = Sort(intArray.AsEnumerable(), SortInt); 
}

public static IEnumerable<T> Sort<T>(
              IEnumerable<T> toBeSorted, 
              Func<IEnumerable<T>, IEnumerable<T>> sortFunc) 
{        
   return sortFunc(toBeSorted);
}

public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array) 
{    
    return array.OrderByDescending(x => x);
}

私は上記を好む、しかしこれは私があなたのサンプルに到達することができる最も近いものであり、それはうまくいく:

  void Main() {
    var intArray = new [] { 1, 3, 2, 5, 1 };
    var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
    var nextInts = Sort<int, int>(intArray.AsEnumerable(), SortInt); 
   }

   public static IEnumerable<TResult> Sort<T, TResult>(
                 IEnumerable<T> toBeSorted, 
                 Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
   {    
      return sortFunc(toBeSorted);
   }
   public static IEnumerable<int> SortInt(IEnumerable<int> array){    
      return array.OrderByDescending(x => x);
   }

SortIntは次のようにもなります。

public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array){    
   return array.OrderByDescending(x => x);
}

Akashは、ラムダ式を使用したときに違いが生じる理由について説明しています。

関連する質問

最近の質問