将动态对象传递给C#方法会更改返回类型

本文关键字:方法 返回类型 动态 对象 | 更新日期: 2023-09-27 18:22:08

我创建了一个继承DynamicObject的类,并希望创建一个静态方法,该方法可以创建具有预定属性的新实例(存储在Dictionary中)。

public class CustomDynamic : DynamicObject
{
    protected Dictionary<string, object> InnerDictionary;
    public static T Create<T>(Dictionary<string, object> dictionary) where T : CustomDynamic , new()
    {
        return new T
        {
            InnerDictionary = dictionary
        };
    }
}

用法:

dynamic d = new Dictionary<string, object>();
var realPlayer = CustomDynamic.Create<Player>(d as Dictionary<string, object>);
var dynaPlayer = CustomDynamic.Create<Player>(d);
realPlayer // Player type according to VS2013
dynaPlayer // dynamic type according to VS2013

既然只有一个方法签名,为什么传入动态会返回动态对象?或者实际上只是Visual Studio 2013被搞糊涂了?

将动态对象传递给C#方法会更改返回类型

这是因为几乎任何涉及动态值的操作都是在执行时动态解析的。对于编译时实际上只有一个方法的情况,没有例外;这样语言更简单。(对于某些调用,编译器确实在编译时执行了足够的解析,以确保至少有一个方法具有适当数量的参数——这在第7.5.4节的C#5规范中有规定,但这不会影响有效的返回类型。)

根据C#5规范第7.6.5节:

如果以下至少一项成立,调用表达式将动态绑定:

  • 主表达式具有编译时类型dynamic
  • 可选参数列表中至少有一个参数的编译时类型为dynamic,而主表达式没有委托类型

在这种情况下,编译器将调用表达式分类为dynamic类型的值。[…]

有一些操作涉及动态值,这些值仍然具有非动态总体类型。例如:

  • d is Foo总是bool
  • d as Foo总是Foo
  • new Foo(d)始终是Foo,即使要使用的确切构造函数是在执行时确定的

但是,任何方法调用都被视为返回类型为dynamic

这就是动态的工作方式。来自MSDN

如果方法调用中的一个或多个参数的类型为dynamic,或者方法调用的接收器的类型为dynamic,则重载解析将在运行时发生,而不是在编译时发生。

您可能认为您的方法没有任何额外的重载,但您可能有。编译器在编译时不执行该检查,所以这就是为什么您将dynaPlayer的类型看作是动态的而不是Player