简体   繁体   English

奇数行为随var,dynamic和linq组合而变化

[英]Odd behaviour change with var, dynamic and linq combination

I (lazily) used var in the original version of the below code and got a strange runtime exception in an entirely different part of the code. 我(懒惰地)在下面代码的原始版本中使用了var ,并在代码的完全不同的部分得到了一个奇怪的运行时异常。 Changing "var" to "int" fixed the runtime exception but I cannot quite see why. 将“var”更改为“int”修复了运行时异常,但我不明白为什么。 I boiled the code down to this example; 我把代码煮成了这个例子;

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());
    }
}

I can see the type of the "var" being dynamic instead of int, but why does that type propagate to and affect the behaviour of the return value of the call to Test() ? 我可以看到“var”的类型是动态的而不是int,但是为什么该类型传播到并影响对Test()的调用的返回值的行为?

EDIT: Maybe I should clarify my question; 编辑:也许我应该澄清我的问题; I can see that dynamic propagates to result2 , what I cannot understand is why, when the IDE clearly indicates that List<string> Test(string) is the method called, it still infers the return value as dynamic. 我可以看到dynamic传播到result2 ,我无法理解为什么,当IDE明确指出List<string> Test(string)是被调用的方法时,它仍然将返回值推断为动态。 Is it a case of the IDE being more clever than the compiler? 这是IDE比编译器更聪明的情况吗?

The problem is that First is an extension method not an instance method and runtime binder has trouble differentiating extension methods from instance methods dynamically. 问题是First是一个扩展方法而不是实例方法,并且运行时绑定器无法动态区分扩展方法和实例方法。

you can read more on this here: 你可以在这里阅读更多内容:

Extension method and dynamic object 扩展方法和动态对象

Your code is compiled like this: 您的代码编译如下:

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 is a dynamic object, then extention method is not supported on it (used as extention method). result2是一个动态对象,然后不支持扩展方法(用作扩展方法)。

However, you can do this: 但是,您可以这样做:

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

UPDATE UPDATE

Your IDE is not so clever. 你的IDE不是那么聪明。 Try to add the new method: 尝试添加新方法:

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

It will propose you the two possibilities. 它将为您提供两种可能性。

UPDATE2 UPDATE2

Paragraph 7.6.5 of the C# specification: C#规范第7.6.5段:

An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds: 如果至少满足下列条件之一,则动态绑定调用表达式(第7.2.2节):

  • The primary-expression has compile-time type dynamic. primary-expression具有编译时类型dynamic。
  • At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type. 可选参数列表的至少一个参数具有编译时类型dynamic,而primary-expression没有委托类型。

You can see the below iamge shows obviously what could be the problem. 你可以看到下面的iamge显然可能是什么问题。

GetType()值

The GetType() of result2 that shows it was dynamic object. 结果2的GetType()显示它是动态对象。

Also, dynamic keyword doesn't provide support for extension methods 此外,dynamic关键字不提供对扩展方法的支持

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM