Hai*_*yen 5 c# dynamic-keyword
你能否告诉我一些C#中动态类型限制的原因?我在"Pro C#2010和.NET 4平台"中读到了它们.这是摘录(如果引用书籍在这里是非法的,请告诉我,我将删除摘录):
虽然可以使用dynamic关键字定义很多东西,但是它的使用存在一些限制.虽然它们不是show stoppers,但要知道动态数据项在调用方法时不能使用lambda表达式或C#匿名方法.例如,以下代码将始终导致错误,即使目标方法确实采用了一个带有字符串值并返回void的委托参数.
Run Code Online (Sandbox Code Playgroud)dynamic a = GetDynamicObject(); // Error! Methods on dynamic data can’t use lambdas! a.Method(arg => Console.WriteLine(arg));要绕过此限制,您需要使用第11章(匿名方法和lambda表达式等)中描述的技术直接使用底层委托.另一个限制是动态数据点无法理解任何扩展方法(参见第12章).不幸的是,这还包括来自LINQ API的任何扩展方法.因此,使用dynamic关键字声明的变量在LINQ to Objects和其他LINQ技术中的使用非常有限:
Run Code Online (Sandbox Code Playgroud)dynamic a = GetDynamicObject(); // Error! Dynamic data can’t find the Select() extension method! var data = from d in a select d;
提前致谢.
Eri*_*ert 16
托马斯的推测非常好.他对推广方法的推理是现场的.基本上,为了使扩展方法起作用,我们需要调用站点在运行时以某种方式知道在编译时使用指令是什么.我们根本没有足够的时间或预算来开发一个系统,可以将这些信息保存到呼叫站点.
对于lambda,情况实际上比确定lambda是表达树还是委托的简单问题更复杂.考虑以下:
d.M(123)
Run Code Online (Sandbox Code Playgroud)
其中d是动态类型的表达式.*什么对象应该在运行时作为调用站点"M"的参数传递?很明显,我们选择了123并通过了.然后运行时绑定程序中的重载解析算法查看d的运行时类型和int 123的编译时类型并使用它.
现在怎么样呢
d.M(x=>x.Foo())
Run Code Online (Sandbox Code Playgroud)
我们应该将什么对象作为参数传递?我们无法表示"一个变量的lambda方法,它调用一个名为Foo的未知函数,无论x的类型是什么".
假设我们想要实现这个功能:我们要实现什么?首先,我们需要一种方法来表示一个未绑定的lambda.表达树仅用于表示已知所有类型和方法的lambda.我们需要发明一种新的"无类型"表达式树.然后我们需要在运行时绑定器中实现lambda绑定的所有规则.
考虑最后一点.Lambdas可以包含语句. 实现此功能要求运行时绑定程序包含C#中每个可能语句的整个语义分析器.
这是我们预算中的数量级.如果我们想要实现该功能,我们今天仍然会在C#4上工作.
不幸的是,这意味着LINQ在动态方面不能很好地工作,因为LINQ当然会在所有地方使用无类型的lambda.希望在一些假设的未来版本的C#中,我们将拥有一个功能更全面的运行时绑定器,并能够对未绑定的lambdas进行同色表示.但如果我是你,我不会屏住呼吸.
更新:评论要求澄清关于语义分析器的观点.
考虑以下重载:
class C {
public void M(Func<IDisposable, int> f) { ... }
public void M(Func<int, int> f) { ... }
...
}
Run Code Online (Sandbox Code Playgroud)
和一个电话
d.M(x=> { using(x) { return 123; } });
Run Code Online (Sandbox Code Playgroud)
假设d是编译时类型动态和运行时类型C.运行时绑定器必须做什么?
运行时绑定程序必须在运行时确定表达式x=>{...}是否可转换为M的每个重载中的每个委托类型.
为此,运行时绑定程序必须能够确定第二个重载不适用.如果它适用,那么你可以使用int作为using语句的参数,但using语句的参数必须是一次性的.这意味着运行时绑定程序必须知道using语句的所有规则,并能够正确地报告对using语句的任何可能使用是合法还是非法.
显然,这不仅限于使用声明.运行时绑定程序必须知道所有C#的所有规则,以确定给定的语句lambda是否可转换为给定的委托类型.
我们没有时间编写一个运行时绑定程序,它本质上是一个生成DLR树而不是IL的全新C#编译器.通过不允许lambdas,我们只需要编写一个运行时绑定器,它知道如何绑定方法调用,算术表达式和一些其他简单的调用站点.允许lambda使得运行时绑定的问题实现,测试和维护的成本要高几十倍或几百倍.
Lambdas:我认为不支持lambdas作为动态对象参数的一个原因是编译器不知道是将lambda编译为委托还是表达式树.
使用lambda时,编译器根据目标参数或变量的类型决定.当它Func<...>(或其他委托)时,它将lambda编译为可执行委托.当目标是Expression<...>它时,它将lambda编译成表达式树.
现在,当你有一个dynamic类型时,你不知道参数是委托还是表达式,所以编译器无法决定做什么!
扩展方法:我认为这里的原因是在运行时查找扩展方法将非常困难(并且可能也是低效的).首先,运行时需要知道使用哪些名称空间using.然后,它需要搜索所有已加载程序集中的所有类,过滤那些可访问的(通过命名空间),然后搜索那些扩展方法...
| 归档时间: |
|
| 查看次数: |
3328 次 |
| 最近记录: |