在函数内部进行动态调用可以防止静态上下文检查。为什么?

时间:2015-08-06 21:08:59

标签: c# dynamic static

我有以下代码。使用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。

对行为的任何解释?

2 个答案:

答案 0 :(得分:4)

仍然在编译时使用dynamic执行重载分辨率,以提供可以调用的潜在函数的列表。在运行时,根据dynamic的实际类型将列表缩小到最佳。

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

  1. 辅助功能检查
  2. 重载决议
  3. 静态检查
  4. 由于dynamic会影响重载决策(步骤#2),但在编译时无法缩小到最佳候选者,似乎static检查(#3)也会延迟到运行时

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

    即使它不是一个真正的错误 1 ,我认为这违反了dynamic的设计原则 - 我一直都理解为只推迟你别无选择的错误推迟。

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

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

答案 1 :(得分:0)

由于SomeFunc(DateTime)的参数类型为DateTime,因此您无法为其提供dynamic个对象。它期望DateTime,所以你必须对其进行类型转换。 编辑:实际上,这不是真的,因为Chris Sinclair指出你可以像这样使用dynamic。我的其余部分仍然适用

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

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