动态参数和返回类型

时间:2015-03-04 21:39:48

标签: c# dynamic

道歉,如果这是显而易见的,但我无法解决或将正确的搜索词串在一起,以找到我正在寻找的答案。

请考虑以下代码:

public IEnumerable<T> Query<T>(string command, dynamic param = null)
{
  return Enumerable.Empty<T>();
}

public T FirstOrDefault<T>(string command, dynamic param = null)
{
  return Query<T>(command, param).FirstOrDefault();
}

Linq的{​​{1}}扩展方法FirstOrDefault未被提取,大概是因为动态参数,但我无法理解原因。

该方法的Intellisense声明它将在运行时解析,但我不理解为什么返回值受动态参数的影响,因为它只是传递的参数。

enter image description here

有人能让我摆脱痛苦吗?

3 个答案:

答案 0 :(得分:1)

您无法在dynamic类型的对象上调用扩展方法。扩展方法是纯编译时构造。在运行时,它将搜索名为FirstOrDefault的实例方法,而不是找到一个,因此输出错误。

您的解决方案要么在调用Query之前将FirstOrDefault的结果转换为适当的类型,要么不使用扩展方法语法,而是写出:Queryable.FirstOrDefault(Query<T>(...))将告诉运行时绑定程序它正在尝试将Query的结果绑定到适当的静态方法,而不是实例方法。

至于为什么接受dynamic类型参数的任何方法总是解析为dynamic类型的表达式:这就是规范所说的。使用dynamic的整个是将方法的绑定推迟到运行时,因此在运行时之前无法确定该表达式的值是什么;为了解决这个问题,它需要传播dynamic类型。

答案 1 :(得分:1)

问题在于,由于您使用dynamic调用了方法,因此返回将为dynamic,因此CLR可以确定在运行时使用的正确方法重载,这可能会导致返回的变化类型。

这意味着您无法直接调用.FirstOrDefault,因为该方法在类中不存在,它是一种扩展方法(并且看到了机器人IEnumerableIQueryable形式,模糊的延伸)。虽然它很方便,但动态类型不会查找扩展方法,只能在运行时在类上定义扩展方法。

解决此问题的一种方法是将Extension方法作为静态方法调用:

return Enumerable.FirstOrDefault(Query<T>(command, param));

不那么优雅,但由于所有扩展方法都是静态方法,这应该可以解决您的问题。

答案 2 :(得分:0)

因为C#有方法重载:要调用的正确方法由参数的静态类型决定。 intellisense可能是聪明的,并发现实际上只有一个候选人,但显然它不是那么聪明。

动态语言有很好的智能感知实现,比如PHP(Visual Studio的PHP工具),Python,他们可以处理类似的事情。我认为dynamic预计会被稀疏地用于真正动态的情况,因此C#intellisense的作者并没有费心去实现这种聪明的分析。