5

私は(怠惰に)var以下のコードの元のバージョンで使用し、コードのまったく異なる部分で奇妙なランタイム例外を受け取りました。「var」を「int」に変更すると、ランタイム例外が修正されましたが、その理由がよくわかりません。コードをこの例に要約しました。

public class Program
{
    private static List<string> Test(string i) { return new List<string> {i}; }
    private static dynamic GetD() { return 1; }

    public static void Main()
    {
        int value1 = GetD();   // <-- int
        var result1 = Test("Value " + value1);
        // No problem, prints "Value 1", First() on List<string> works ok.
        Console.WriteLine(result1.First());

        var value2 = GetD();   // <-- var
        var result2 = Test("Value " + value2);
        // The below line gives RuntimeBinderException 
        // 'System.Collections.Generic.List<string>' does not contain a 
        // definition for 'First'
        Console.WriteLine(result2.First());
    }
}

「var」の型がintではなく動的であることがわかりますが、なぜその型がに伝播し、への呼び出しの戻り値の動作に影響を与えるのTest()ですか?

編集:たぶん私は私の質問を明確にする必要があります。にdynamic伝播するresult2ことがわかりますが、理解できないのは、IDEがList<string> Test(string)呼び出されたメソッドであることを明確に示している場合でも、戻り値が動的であると推測する理由です。IDEがコンパイラよりも賢い場合ですか?

4

3 に答える 3

2

問題は、Firstがインスタンスメソッドではなく拡張メソッドであり、ランタイムバインダーが拡張メソッドをインスタンスメソッドから動的に区別するのに問題があることです。

あなたはここでこれについてもっと読むことができます:

拡張メソッドと動的オブジェクト

于 2013-01-26T10:15:59.597 に答える
2

コードは次のようにコンパイルされます。

public static void Main()
{
    int value1 = GetD();   // <-- int
    List<string> result1 = Test("Value " + value1);
    // No problem, prints "Value 1", First() on List<string> works ok.
    Console.WriteLine(result1.First());

    dynamic value2 = GetD();   // <-- var
    dynamic result2 = Test("Value " + value2);
    // The below line gives RuntimeBinderException 
    // 'System.Collections.Generic.List<string>' does not contain a 
    // definition for 'First'
    Console.WriteLine(result2.First());
}

result2は動的オブジェクトであるため、拡張メソッドはサポートされていません(拡張メソッドとして使用されます)。

ただし、これを行うことができます。

Console.WriteLine(Enumerable.First(result2));

アップデート

あなたのIDEはそれほど賢くありません。新しいメソッドを追加してみてください。

private static List<int> Test(int i) { return new List<int> { i }; }

それはあなたに2つの可能性を提案します。

UPDATE2

C#仕様の7.6.5項:

次の少なくとも1つが当てはまる場合、呼び出し式は動的にバインドされます(§7.2.2)。

  • プライマリ式のコンパイル時の型は動的です。
  • オプションのargument-listの少なくとも1つの引数には、コンパイル時の型が動的であり、primary-expressionにはデリゲート型がありません。
于 2013-01-26T10:18:17.833 に答える
0

以下の画像は、何が問題であるかを明らかに示しています。

GetType()値

それが動的オブジェクトであることを示すresult2のGetType()。

また、動的キーワードは拡張メソッドのサポートを提供しません

于 2013-01-26T12:48:17.080 に答える