函数内部存在动态调用会阻止静态上下文 checking.Why?

Presence of dynamic call inside a function prevents static context checking.Why?

我有以下代码。使用Visual Studio 2013.请注意函数

中的动态函数调用
class Someclass
{
   public static string[] BuildParametersString(ISomeInterface obj1, ISecondInterface obj2)
   {
      //.....

      var dt = obj1.GetDate();//this returns a dynamic type.
      SomeFunc(dt);//Run time error
   } 

   private string SomeFunc(DateTime somedate)
   {
     //......
   }
}

运行时错误(在 SomeFunc(dt);):非静态字段、方法或 属性.

需要对象引用

如果我替换下面的代码

 var dt = obj1.GetDate();//this returns a dynamic type.

有了这个

DateTime dt = DateTime.Now;

我遇到编译器错误(在 SomeFunc(dt))

无法在静态上下文中访问非静态方法 SomeFunc。

对这种行为有任何解释吗?

因为 SomeFunc(DateTime)DateTime 作为它的参数类型,你不能给它一个 dynamic 对象。它需要 DateTime,因此您必须对其进行类型转换。 编辑:实际上,这不是真的,正如 Chris Sinclair 指出的那样,您可以像这样使用 dynamic 。我的其余答案仍然有效

您也不能从静态方法访问实例方法 SomeFunc(DateTime),因为实例方法可能依赖静态上下文中不存在的实例变量。使 SomeFunc(DateTime) 静态化(如果可能)或使 BuildParametersString(ISomeInterface, ISecondInterface) 成为实例方法(或者只是 return 来自 GetDate() 的结果并将其作为参数发送给 SomeFunc(DateTime)来自客户端代码。

我不知道这是否只是一个说明问题的例子,但在这种情况下我也会认真地重新考虑使用动态变量。你从中有什么收获吗?通常应不惜一切代价避免使用它们,因为它们只会使事情复杂化,并且您会丢失所有编译时检查。

重载解析仍会在编译时使用 dynamic 执行,以给出可以调用的潜在函数列表。在运行时,列表会根据 dynamic.

的实际类型缩小到最佳范围

然而,根据规范,重载决议只考虑参数的数量和类型——而不是 static 甚至可访问性。根据一些快速测试,编译时的操作顺序似乎是:

  1. 辅助功能检查
  2. 过载分辨率
  3. 静态检查

由于 dynamic 影响重载决议(步骤 #2),但无法在编译时缩小到最佳候选范围,因此 static 检查(#3)似乎也被推迟直到运行时。

我在理论上看不出有任何理由无法重新排序这些步骤(注意:我不知道是否有相关规范需要考虑),或者无法执行第 3 步(在编译时)针对来自“动态”重载决议的所有可能候选人,以确保至少保留一名候选人。

即使它不是真正的错误1,我确实认为它违背了 dynamic 的设计原则——我一直认为它只是推迟什么你别无选择,只能推迟。

更新:请注意,LINQPad 5/VS2015 中的 C# 6 编译器现在会在编译时对此进行标记;尽管操作顺序似乎没有改变。

1C# 5 规范第 7.6.5.1 节(方法调用)指定 "final validation"(包括静态检查)发生在重载解析之后; 7.5.4节(动态重载决议的编译时检查)仅指定对带有动态参数的方法调用执行部分类型推断和部分适用性检查(重载决议)。