在C#的动态类型的局限性 [英] Limitations of the dynamic type in C#

查看:219
本文介绍了在C#的动态类型的局限性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你能不能给我一些原因,在C#中动态类型的限制?我在临C#2010和.NET 4平台了解他们。下面是摘录(如果引用的书籍是非法的在这里,告诉我,我会删除节选):




虽然很多事情可以可以使用动态关键字
定义,
有关于
它的使用有一些限制。虽然他们没有表现出
瓶塞,知道,调用方法时,动态数据
项不能利用拉姆达
表达式或C#匿名方法
的。例如,
下面的代码总是会导致错误
,即使目标的方法
确实采取了委托参数
,它接受一个字符串值,并返回
无效。

 动态A = GetDynamicObject(); 
//错误!动态数据的方法不能使用lambda表达式!
a.Method(ARG => Console.WriteLine(ARG));

要绕过这个限制,你
将需要与底层
工作直接委派,使用在第11章
中描述的
技术(匿名方法和lambda
表情等)。另一个限制
是该数据的动态点不能
明白任何扩展方法(见
第12章)。不幸的是,这将
还包括任何的延伸
方法,其中来自LINQ的API。
因此,
动态关键字声明一个变量中的LINQ to Objects和其他
LINQ技术非常有限
使用:

 动态A = GetDynamicObject(); 
//错误!动态数据找不到选择()扩展方法!从在选择D D
VAR数据=;




在此先感谢。


< DIV CLASS =h2_lin>解决方案

托马斯的猜测都还不错。他对扩展方法推理即期。基本上,使扩展方法工作,我们需要调用站点在运行时的在某种程度上知道什么是使用指令已经生效在编译时间的。我们根本没有足够的时间或预算来制定一个制度,这个信息可以持续到调用站点。



有关lambda表达式,情况其实比更复杂确定拉姆达是否会表达式树或委托的简单的问题。考虑以下几点:

  DM(123)

其中d是类型的动态的表达。 *什么对象应在运行时获得通过作为参数调用点M?显然,我们盒123和传递。然后在运行时绑定的重载解析算法着眼于运行时类型D和编译时类型的INT 123,并与工作。



现在如果它是

  DM(X => x.Foo())

现在,我们应该通过什么样的对象作为参数?我们没有办法来表示该呼吁无论x的类型原来是叫Foo的一个未知函数的一个变量的拉姆达方法。



假设我们要实现此功能:我们将不得不实施?首先,我们需要一种方法来表示的未绑定的lambda 的。表达式树是由设计,只为所有类型和方法被称为代表的的lambda 的。我们就需要发明一种新的类型化表达式树的。然后我们就需要实现的所有的规则为拉姆达在运行时绑定绑定。



考虑最后一点。的 Lambda表达式可以包含语句的。 实现此功能要求运行时绑定包含的全部的语义分析仪的每一个可能的的在C#中声明



这是数量级的了我们的预算。我们还是会在C#4今天工作,如果我们会想实现该功能。



不幸的是,这意味着LINQ不动很好地工作,因为当然LINQ使用非类型化的lambda表达式所有的地方。希望在C#中,一些假想的未来版本中,我们将有更全功能运行时绑定和非绑定做lambda表达式homoiconic交涉的能力。但我不认为我的呼吸等待,如果我是你,



更​​新:有意见要求澄清有关语义分析点



考虑以下重载:

  C类{
公共无效M(Func键< ; IDisposable接口,INT&F)的温度{...}
公共无效M(Func键< INT,INT&F)的温度{...}

}

和通话

  DM(X => {用(X){返回123;}}); 



假设d为编译时动态类型和运行时类型C.什么必须在运行时绑定呢?



在运行时绑定必须确定的在运行时的是否表达 X => {...} 是在每个分枝



的重载可转换到每个委托类型。为了做到这一点,运行时粘合剂必须能够确定该第二个重载不适用。如果是适用的,那么你可以有一个int作为参数using语句,但参数using语句必须是一次性的。这意味着,在运行时绑定的必须知道using语句的所有规则,并能够正确地报告任何可能使用using语句是否是合法或非法的的。



清楚,并不限于using语句。在运行时绑定必须知道的所有的所有的C#的规则,以确定给定语句的lambda是否可以转换为给定的委托类型。



我们没有时间来写一个运行时绑定的基本上的一个全新的C#编译器生成DLR树,而不是IL 的。通过不允许lambda表达式,我们只需要编写一个知道如何绑定方法调用,算术表达式和其他一些简单的调用各类站点的运行时绑定。允许lambda表达式使得运行时数十或数百次更昂贵的顺序来实现,测试和维护上结合的问题。


Could you give me some reasons for limitations of the dynamic type in C#? I read about them in "Pro C# 2010 and the .NET 4 platform". Here is an excerpt (if quoting books is illegal here, tell me and I will remove the excerpt):

While a great many things can be defined using the dynamic keyword, there are some limitations regarding its usage. While they are not show stoppers, do know that a dynamic data item cannot make use of lambda expressions or C# anonymous methods when calling a method. For example, the following code will always result in errors, even if the target method does indeed take a delegate parameter which takes a string value and returns void.

dynamic a = GetDynamicObject(); 
// Error!  Methods on dynamic data can’t use lambdas! 
a.Method(arg => Console.WriteLine(arg));

To circumvent this restriction, you will need to work with the underlying delegate directly, using the techniques described in Chapter 11 (anonymous methods and lambda expressions, etc). Another limitation is that a dynamic point of data cannot understand any extension methods (see Chapter 12). Unfortunately, this would also include any of the extension methods which come from the LINQ APIs. Therefore, a variable declared with the dynamic keyword has very limited use within LINQ to Objects and other LINQ technologies:

dynamic a = GetDynamicObject(); 
// Error!  Dynamic data can’t find the Select() extension method! 
var data = from d in a select d;

Thanks in advance.

解决方案

Tomas's conjectures are pretty good. His reasoning on extension methods is spot on. Basically, to make extension methods work we need the call site to at runtime somehow know what using directives were in force at compile time. We simply did not have enough time or budget to develop a system whereby this information could be persisted into the call site.

For lambdas, the situation is actually more complex than the simple problem of determining whether the lambda is going to expression tree or delegate. Consider the following:

d.M(123)

where d is an expression of type dynamic. *What object should get passed at runtime as the argument to the call site "M"? Clearly we box 123 and pass that. Then the overload resolution algorithm in the runtime binder looks at the runtime type of d and the compile-time type of the int 123 and works with that.

Now what if it was

d.M(x=>x.Foo())

Now what object should we pass as the argument? We have no way to represent "lambda method of one variable that calls an unknown function called Foo on whatever the type of x turns out to be".

Suppose we wanted to implement this feature: what would we have to implement? First, we'd need a way to represent an unbound lambda. Expression trees are by design only for representing lambdas where all types and methods are known. We'd need to invent a new kind of "untyped" expression tree. And then we'd need to implement all of the rules for lambda binding in the runtime binder.

Consider that last point. Lambdas can contain statements. Implementing this feature requires that the runtime binder contain the entire semantic analyzer for every possible statement in C#.

That was orders of magnitude out of our budget. We'd still be working on C# 4 today if we'd wanted to implement that feature.

Unfortunately this means that LINQ doesn't work very well with dynamic, because LINQ of course uses untyped lambdas all over the place. Hopefully in some hypothetical future version of C# we will have a more fully-featured runtime binder and the ability to do homoiconic representations of unbound lambdas. But I wouldn't hold my breath waiting if I were you.

UPDATE: A comment asks for clarification on the point about the semantic analyzer.

Consider the following overloads:

class C {
  public void M(Func<IDisposable, int> f) { ... }
  public void M(Func<int, int> f) { ... }
  ...
}

and a call

d.M(x=> { using(x) { return 123; } });

Suppose d is of compile time type dynamic and runtime type C. What must the runtime binder do?

The runtime binder must determine at runtime whether the expression x=>{...} is convertible to each of the delegate types in each of the overloads of M.

In order to do that, the runtime binder must be able to determine that the second overload is not applicable. If it were applicable then you could have an int as the argument to a using statement, but the argument to a using statement must be disposable. That means that the runtime binder must know all the rules for the using statement and be able to correctly report whether any possible use of the using statement is legal or illegal.

Clearly that is not restricted to the using statement. The runtime binder must know all the rules for all of C# in order to determine whether a given statement lambda is convertible to a given delegate type.

We did not have time to write a runtime binder that was essentially an entire new C# compiler that generates DLR trees rather than IL. By not allowing lambdas we only have to write a runtime binder that knows how to bind method calls, arithmetic expressions and a few other simple kinds of call sites. Allowing lambdas makes the problem of runtime binding on the order of dozens or hundreds of times more expensive to implement, test and maintain.

这篇关于在C#的动态类型的局限性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆