当前位置: 首页 > 编程语言 > C#

C#中动态类型的局限性分享

时间:2023-04-11 02:42:07 C#

C#中动态类型的局限性你能给我一些C#中动态类型局限性的原因吗?我在“ProC#2010andthe.NET4Platform”中读到了它们。这是一段摘录(如果在这里引用一本书是非法的,请告诉我,我会删除摘录):虽然您可以使用dynamic关键字定义很多东西,但它的使用有一些限制。虽然它们不是显示塞子,但要知道动态数据项在调用方法时不能使用lambda表达式或C#匿名方法。例如,以下代码将始终导致错误,即使目标方法确实采用采用字符串值并返回void的委托参数。动态a=GetDynamicObject();//错误!动态数据的方法不能使用lambda!a.Method(arg=>Console.WriteLine(arg));要绕过这个限制,你需要使用第11章(匿名方法、lambda表达式等)直接使用底层委托。另一个限制是动态数据点不??理解任何扩展方法(见第12章)。遗憾的是,这还包括来自LINQAPI的任何扩展方法。因此,使用dynamic关键字声明的变量在LINQtoObjects和其他LINQ技术中的使用非常有限:dynamica=GetDynamicObject();//错误!动态数据找不到Select()扩展方法!vardata=fromdinaselectd;提前致谢。托马斯的猜测非常好。他对晋升方法的推理是正确的。基本上,为了使扩展方法起作用,我们需要调用站点以某种方式在运行时知道在编译时使用什么指令。我们根本没有时间或预算来开发一个系统来将这些信息保存到呼叫站点。对于lambda,情况实际上比判断lambda是表达式树还是委托这个简单问题要复杂。考虑以下内容:dM(123)其中d是一个动态类型的表达式。*在运行时应该将什么对象作为参数传递给调用站点“M”?很明显,我们选了123,通过了。然后运行时绑定器中的重载解析算法查看d的运行时类型和int123的编译时类型,并使用它们。现在dM(x=>x.Foo())我们应该传递什么对象作为参数呢?我们不能表示“调用名为Foo的未知函数的变量的lambda方法,无论x是什么类型”。假设我们要实现这个功能:我们需要实现什么?首先,我们需要一种表示未绑定lambda的方法。表达式树仅用于表示所有类型和方法已知的lambda。我们需要发明一种新的“无类型”表达式树。然后我们需要在运行时绑定器中实现lambda绑定的所有规则。考虑最后一点。Lambda可以包含语句。实现此功能需要运行时绑定程序包含C#中每个可能的语句的整个语义分析器。这在我们的预算中是一个数量级。如果我们想要实现该功能,我们今天仍将致力于C#4。不幸的是,这意味着LINQ不能很好地处理动态,因为LINQ当然到处都使用无类型的lambda。希望在某些假设的C#未来版本中,我们将拥有功能更全面的运行时绑定器,能够为未绑定的lambda着色。但如果我是你,我不会屏住呼吸。更新:要求澄清语义分析器的评论。考虑以下重载:classC{publicvoidM(Funcf){...}publicvoidM(Funcf){...}...}和调用dM(x=>{using(x){返回123;}});假设d是编译时类型dynamic和运行时类型C。运行时绑定器必须做什么?运行时绑定器必须在运行时确定表达式x=>{...}是否可转换为M的每个重载中的每个委托类型。为此,运行时绑定器必须能够确定第二个重载不适用。如果适用,则可以使用int作为using语句的参数,但using语句的参数必须是一次性的。这意味着运行时绑定器必须知道using语句的所有规则,并且能够正确报告使用using语句是合法还是非法。显然,这不仅限于使用声明。运行时绑定器必须了解所有C#规则以确定给定语句lambda是否可转换为给定委托类型。我们没有时间编写运行时绑定器,它本质上是一个全新的C#编译器,它生成DLR树而不是IL。由于不允许lambda,我们只需要编写一个知道如何绑定方法调用、算术表达式和其他一些简单调用站点的运行时绑定器。允许lambda会使运行时绑定问题的实施、测试和维护成本提高数十或数百倍。Lambda:我认为lambda不支持作为动态对象参数的一个原因是编译器不知道是将lambda编译为委托还是表达式树。使用lambda时,编译器根据目标参数或变量的类型来决定。当它是Func(或其他委托)时,它将lambda编译成可执行委托。当目标是Expression时,它将lambda编译成表达式树。现在,当你有一个动态类型时,你不知道参数是委托还是表达式,所以编译器无法决定要做什么!扩展方法:我认为这里的原因是在运行时找到扩展方法非常困难(并且可能效率低下)。首先,运行时需要知道要使用什么命名空间。然后它需要搜索所有加载的程序集中的所有类,过滤那些可访问的(通过命名空间),然后搜索那些扩展方法......Eric(和Thomas)说得很好,但这就是我的想法。这个C#语句a.Method(arg=>Console.WriteLine(arg));没有很多上下文就没有任何意义。Lambda表达式本身没有类型,但可以转换为委托(或表达式)类型。因此,收集含义的唯一方法是提供一些上下文,强制将lambda转换为特定的委托类型。该上下文通常(如本例中)是重载决议;给定a的类型和该类型的可用重载方法(包括扩展成员),我们可以放置一些赋予lambda含义的上下文。如果上下文没有意义,您最终不得不捆绑有关lambda的各种信息,以期在运行时以某种方式绑定未知数。(你可能生成什么IL?)与此形成鲜明对比的是,你在其中放置了一个特定的委托类型,a.Method(newAction(arg=>Console.WriteLine(arg)));点击!事情变得容易了。无论lambda中的代码是什么,我们现在都知道它的类型,这意味着我们可以像编译任何方法体一样编译IL(例如,我们现在知道我们再次调用Console.WriteLine的多个重载中的哪一个)。该代码具有特定类型(Action),这意味着运行时绑定程序很容易查看是否有采用该类型参数的方法。在C#中,裸lambda几乎毫无意义。C#lambda需要一个静态上下文来赋予它们意义,并排除由许多可能的强制转换和重载引起的歧义。典型的程序很容易提供这种背景,但动态案例缺乏这种重要的背景。以上就是《C#学习教程:C#中动态类型的限制》的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: