函数内部的动态调用阻止了静态上下文检查.为什么?

本文关键字:上下文 静态 检查 为什么 内部 动态 调用 函数 | 更新日期: 2023-09-27 18:06:41

我有以下代码。使用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)
   {
     //......
   }
}

运行时错误(at SomeFunc(dt);):非静态字段、方法或属性需要对象引用。

如果我替换下面的代码

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

DateTime dt = DateTime.Now;

我得到一个编译器错误(在SomeFunc(dt))

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

对这种行为有什么解释吗?

函数内部的动态调用阻止了静态上下文检查.为什么?

对于dynamic,仍然在编译时执行重载解析,以给出可以调用的潜在函数列表。在运行时,根据dynamic的实际类型将列表缩小到最佳。

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

由于dynamic影响过载解析(步骤#2),但不能在编译时缩小到可能的最佳候选,因此static检查(#3)似乎也延迟到运行时。

我看不出有任何理由在理论上说这些步骤不能重新排序(注:我不知道是否有相关的规范要考虑),或者步骤#3不能(在编译时)针对"动态"重载解析中出现的所有可能的候选对象执行,以确保至少有一个候选对象保留。

即使它不是一个真正的bug1,我确实认为它违背了dynamic的设计原则——我一直认为这是只推迟你别无选择只能推迟的事情。

更新:注意,LINQPad 5/VS2015中的c# 6编译器现在在编译时标记此;虽然操作顺序似乎没有改变。

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

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

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

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