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

C# 规范的第 7.6.5 段:

如果以下至少一项成立,则调用表达式是动态绑定的(第 7.2.2 节):

  • 主表达式具有编译时类型动态。
  • 可选参数列表的至少一个参数具有编译时类型动态,并且主表达式没有委托类型。
于 2013-01-26T10:18:17.833 回答
0

您可以看到下面的 iamge 清楚地显示了可能是什么问题。

GetType() 值

result2 的 GetType() 表明它是动态对象。

此外,动态关键字不支持扩展方法

于 2013-01-26T12:48:17.080 回答