2016-07-22 11 views
1

私は以下のサンプルを持っています。これが原因でエラーが発生するのはなぜですか?CS4011:型引数は使用から推測できませんか?

class Program { 
    static void Main(string[] args) { 
     var varc = new C(); 
     // Error CS0411 
     var varf1b = varc.F1(t => new { City = t.City }, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a }); 
     // compiles OK 
     var varf1a = varc.F1(t => new { City = t.City }, (C t, int v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a }); 

     // now replace varc by an anonymous class -- how to solve it now? 
     var varanon = new { }; 

    } 
    } 

    public class C { 
    public string City; 
    public int Status; 
    } 

    public static class X { 
    public static T1 F1<T2, T3, T4, T1>(
     this T2 s, 
     Func<T2, T3> g, 
     Func<T2, T4, T4> a, 
     Func<T3, T4, T1> r) 
     where T2 : class where T3 : class where T1 : class { 
     return null; 
    } 
    } 

最初の呼び出しでエラーCS0411が発生します。匿名型を使用しているため、型引数を追加する通常の方法ではこれを修正できません。幸いなことに、lambdaの1つに型を追加することは、コンパイラを満足させるのに十分なようです。

なぜですか?具体的には最初の例は失敗し、2番目は成功するでしょうか?

第二に、これは起こらないように関数呼び出しを書くための方法がありますか?ユーザーはラムダに型を挿入する必要がありませんか?

はい、他の人が同様の質問をしましたが、ここではユニークなのは(a)ラムダに型を追加することによる修正(b)匿名型の使用です。編集


:与えられた解決策の問題は、可能な型注釈が存在しないので、それが匿名クラスで使用することはできませんということです。

+1

このように見て、あなたは 'v'が' int'型であることをコンパイラが知っていることを期待しています。しかし、なぜそれができるはずですか? 'T4'は簡単に' long'、 'double'、' decimal'、または加算演算子に整数でオーバーロードする他の型にすることができます。 –

+0

@JeffMercado:いいえ、そうではありません。コンパイラは式の形式には興味がありません。エラーを変更することなく、何か(有効)で置き換えることができます。 –

+0

私の主張は、コンパイラがあなたのために型を決めるのが遠すぎないようにすることです。少なくとも、他の言語ほどではありません。それが試しても、その選択があいまいなので成功しないでしょう。それは完全に知られているあなたが提供したタイプのみを使用します。入力タイプに関する情報を提供することはできませんが、出力タイプとそれだけでは、 'T4'は十分な情報ではない' int'を持つ 'T4'を追加した結果かもしれません。 –

答えて

1

質問:vの種類は何ですか?

コンパイラは、出力として使用される式からの入力のタイプを推論しません。コンパイラは、推論された型の入力を使用して、出力に対して有効な式を書くことができます。

var varf1b = varc.F1(t => new { City = t.City }, (C t, int v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });   
        |   |     |  |     | |       | 
        |   |     |  |     | |       | 
       T2: C (varc)  |     | T4: int    | T4: int     | 
           |     |       |     T1: new { string City, int Bigstatus } 
         T3: new { string City }  |       | 
                T2: C      | 
                      T3: new { string City } 
:これは、コンパイラは2番目の試みを分析しようとしている

var varf1b = varc.F1(t => new { City = t.City }, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });   
        |   |     | |     | |       | 
        |   |     | |     | |       | 
       T2: C (varc)  |     | ?     | ?       | 
           |     |      |     T1: new { string City, ? Bigstatus } 
         T3: new { string City }  |      | 
               T2: C     | 
                    T3: new { string City } 

:だから、(t, v) => 1vこれは、コンパイラがあなたの最初の試みを分析しようとしているint

タイプであることを意味するものではありません。

だからvarf1bはタイプ:T1: new { string City, int Bigstatus }であり、推論は成功します。

シンプルな例:私は今見る

private static void GenericMethod<T1>(Func<T1, T1> func) 
{ 
    // ... 
} 

GenericMethod((a) => 1); // CS0411, `a` is not inferred from the body of the method. 

GenericMethod<int>((a) => 1); // compiles 

GenericMethod((int a) => 1); // compiles 
+1

コンパイラはaddオペレーションがサポートされていることを知る必要はなく、 'T4'に使用できる*実際の型*を知る必要があることに注意してください。 – poke

+0

@poke '+'メソッドの戻り値の型を知るためです。右 ? – user3185569

+1

それだけでなく、型引数 'T4'を解決するためです。型引数はコンパイル時に "実"型に置き換える必要があります。彼らは一般的にとどまることはできません。 – poke

-1

答えは、コンパイラが、それはT4のタイプを決定するために使用できる情報がありませんということです。特に、式を調べることはできず、それから型を推論することはできません。

これを修正するには、T4のタイプを明示的に設定する引数が必要です。これを行うための一つの方法があります。

var varf1c = varc.F2(t => new { City = t.City }, 0, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a }); 

public static T1 F2<T2, T3, T4, T1>(
    this T2 s, 
    Func<T2, T3> g, 
    T4 i, 
    Func<T2, T4, T4> a, 
    Func<T3, T4, T1> r) 
    where T2 : class where T3 : class where T1 : class { 
    return null; 
} 

次にT4は、コンパイラがintの種類を推測することができ、そこからリテラル引数0、関連付けられています。

+0

パブリックAPIを変更していくつかの型を残すことは、これを解決するためのひどい方法です。あなたが質問で行ったように、型を明示的に指定するだけで、あなたは大丈夫です。 – poke

+0

@poke:いいえ、それは質問に対する答えではありません(編集を参照)。匿名クラスが関わっているときに型アノテーションを使用することはできないので、_function宣言_を修正して型推論を有効にして型名を避ける方法を見つけることがポイントです。明らかにあなたはそれを逃した。 –

関連する問題