2013-09-25 10 views
7

私はパラメータとして二つの機能を取り、新しい合成1を返す関数で働いている:私はそれ送信するときに、私は、Tを指定しない場合、コンパイラは文句を言いことに気付きましたC#コンパイラが汎用シグネチャの代理人を推論できないのはなぜですか?

public static Action<T> Compose<T>(Action<T> first, Action second) 
{ 
    return new Action<T>(arg => 
    { 
     first(arg); 
     second(); 
    }); 
} 

静的またはメンバ関数(実際Action<T>オブジェクトとは対照的に):

static void Main(string[] args) 
{ 
    // compiler error here 
    var composed = Compose(Test,() => Console.WriteLine(" world")); 
    composed("hello"); 

    Console.ReadLine(); 
} 

public static void Test(string arg) 
{ 
    Console.Write(arg); 
} 

エラーメッセージ:

The arguments for method 'ConsoleTest.Program.Compose(System.Action, System.Action)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

私の質問:なぜ型引数はここで推論できないのですか? Testの署名はコンパイル時にはわかりますか? Testの代わりに置くことができる機能がありますか?それはその署名があいまいになる原因になりますか?

脚注:私は(this questionに述べたように)私は単にComposenew Action<string>(Test)代わりのTestを送ることができます知っている - 私の質問は、「なぜ」、「どのように私はこれを行うことができます」ではありません。

+1

FYI - 'Compose 'も同様です。 –

+3

この回答を参照してください:http://stackoverflow.com/questions/6229131/why-cant-c-sharp-infer-type-from-this-seemingly-simple-obvious-case – lukegravitt

+0

ありがとう@lukegravitt - そこのトップの答え言語スペックを参照し、Lippert自身がチャイムインします。 – McGarnagle

答えて

6

コンパイラの観点から見ると、少なくともTestは実際には「コンパイラがそれが持つパラメータの種類を決定するまで、実際には「メソッドグループ」であるということが関係していると思います。グループ内にメソッドが1つしかない場合でも、これは当てはまります(現在のスコープでは1つだけTestメソッド)。

守っ:

var composed = Compose<object>(Test,() => Console.WriteLine(" world")); 

はエラーを生成:

The best overloaded method match for ' Compose<object>(System.Action<object>, System.Action) ' has some invalid arguments

Argument 1: cannot convert from 'method group' to ' System.Action<object> '

しかし、これは素晴らしいです:

var composed = Compose<string>(Test,() => Console.WriteLine(" world")); 

私の推測では、コンパイラは、両方の方法のグループ式を参照してくださいということです(Test )と暗黙的に型指定されたジェネリックメソッド呼び出し(Compose)は 'unbある意味では「オンド」。メソッドのグループからどのタイプのメソッドを選択するかは、パラメータのタイプ 'unbound'シグニチャーからComposeに完全には決定できず、Composeのシグニチャータイプタイプパラメーターを判別できません。ステートメント全体をコンパイルするには、どちらか一方がバインドされている必要があります。

+2

あなたは正しい方向にいるようです...これらの行に沿った議論があります:http://stackoverflow.com/a/6231921/1001985 – McGarnagle

0

共分散と関係がある可能性があります。引数の型はTestですが、より具体的な型のデリゲートを作成することをお勧めします。

public class BaseClass { } 
public class DerivedClass : BaseClass { } 

static class Program 
{ 
    static void Main(string[] args) 
    { 
     var composed = Compose<DerivedClass>(Test,() => Console.WriteLine(" world")); 
     composed(new DerivedClass()); 

     Console.ReadLine(); 
    } 

    public static void Test(BaseClass arg) 
    { 
     Console.Write(arg); 
    } 
} 
関連する問題