奇怪的行为随着var,dynamic和linq的组合而改变 [英] Odd behaviour change with var, dynamic and linq combination

查看:135
本文介绍了奇怪的行为随着var,dynamic和linq的组合而改变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码的原始版本中,我(懒洋洋地)使用了 var ,并在代码的完全不同的部分得到了一个奇怪的运行时异常。将var更改为int可以修复运行时异常,但我看不清为什么。我把代码放在这个例子中;

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

public static void Main()
{
int value1 = GetD(); //< - int
var result1 = Test(Value+ value1);
//没问题,打印Value 1,List上的First()< string>工程很好
Console.WriteLine(result1.First());

var value2 = GetD(); //< - var
var result2 = Test(Value+ value2);
//下面的行给出了RuntimeBinderException
//'System.Collections.Generic.List< string>'不包含$'
//'First'
控制台的定义。的WriteLine(result2.First());
}
}

我可以看到var的类型动态而不是int,但为什么这种类型传播到并影响调用返回值的行为 Test()



编辑:也许我应该澄清我的问题;我可以看到,动态传播到 result2 ,我不明白是为什么当IDE清楚地表示列表与LT;串GT; Test(string)是调用的方法,它仍然将返回值推定为动态。这是IDE比编译器更聪明的情况吗?

解决方案

您的代码编译如下:

  public static void Main()
{
int value1 = GetD(); //< - int
列表< string> result1 = Test(Value+ value1);
//没问题,打印Value 1,List上的First()< string>工程很好
Console.WriteLine(result1.First());

动态value2 = GetD(); //< - var
dynamic result2 = Test(Value+ value2);
//下面的行给出了RuntimeBinderException
//'System.Collections.Generic.List< string>'不包含$'
//'First'
控制台的定义。的WriteLine(result2.First());
}

result2 是一个动态对象,那么它不支持扩展方法(用作扩展方法)。



但是,您可以这样做:

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



更新



您的IDE不是聪明。尝试添加新的方法:

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

它将为您提供两种可能性。



更新2



C#规范第7.6.5段:


如果至少有一个
成立,则调用表达式是动态绑定的(§7.2.2):




  • 主要-expression具有编译时类型动态。

  • 可选参数列表的至少一个参数的编译时类型为dynamic,primary-expression不具有委托类型。



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. Changing "var" to "int" fixed the runtime exception but I cannot quite see why. 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()?

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. Is it a case of the IDE being more clever than the compiler?

解决方案

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).

However, you can do this:

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

UPDATE

Your IDE is not so clever. 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

Paragraph 7.6.5 of the C# specification:

An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:

  • The primary-expression has compile-time type 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.

这篇关于奇怪的行为随着var,dynamic和linq的组合而改变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆