扩展方法和动态对象


96

我将在以下代码段中总结我的问题。

List<int> list = new List<int>() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

上面的代码工作正常。

现在我尝试了以下

dynamic dList = list;
 Console.WriteLine(dList.First());

但是我正在得到RuntimeBinderException。为什么会这样呢?


这似乎是这个问题的重复问短短4天前stackoverflow.com/questions/5270782/...
jbtule

@jbtule的区别在于,this这里动态,但是如果您登陆这里,您可能也应该看看这个问题
nik.shornikov 2012年

Answers:


131

为了扩展Stecya的答案...动态类型不以扩展方法的形式来支持扩展方法,即,将其称为实例方法。但是,这将起作用:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

当然,这可能有用也可能没有用。如果您可以提供有关为什么以及如何尝试使用动态类型的更多信息,我们可能会提供更多帮助。


我在玩动态对象,但遇到了这个异常。您是否写过任何有关此主题的文章,在哪里使用或不使用动态对象
santosh singh

19
@geek:就我个人而言,我的经验法则是只dynamic在您真正需要的地方使用...基本上,如果您否则需要通过反思来访问成员,那是一个很大的信号。另一方面,我是一位顽固的静态打字员-其他人可能建议采取较少悲观的政策:)
Jon Skeet

2
强制转换回已知类型可能更易读,这可以正常工作:Console.WriteLine((((List <int>)dList).First()); 或Console.WriteLine((dList as List <int>)。First());。
AVee

138

为了扩展Jon的答案,之所以不起作用,是因为在常规的非动态代码扩展方法中,通过对编译器已知的所有类进行完整搜索以找到具有匹配的扩展方法的静态类,从而可以正常工作。搜索是基于名称空间嵌套和using每个名称空间中的可用指令的顺序进行的。

这意味着为了正确解决动态扩展方法调用,DLR必须在运行时以某种方式知道源代码中所有名称空间的嵌套和using指令是什么。我们没有方便的机制将所有这些信息编码到呼叫站点中。我们考虑过发明这样一种机制,但是认为它成本太高,并且产生了太多计划风险,因此不值得。


非常感谢您的解释。
santosh singh

3
即将推出这样的功能吗?这肯定是一个重大变化。当前引发RunTimeBinderExceptions的调用将在重新编译源代码时突然开始工作。此外,实施此功能会不会有安全隐患?
安仁

5
@ani:我们打算实现该功能吗?否。是否存在安全风险? 我什么都不知道;您想到了什么样的安全风险?首先说明谁是攻击者,以及他们对用户造成的威胁。
Eric Lippert'2

@EricLippert,我知道所有dynamic对象都等于C#:,DynamicObject所以没有办法区分它们,这是为什么无法向加上扩展方法的原因之一dynamic,对吗?
汤姆·萨杜

@EricLippert考虑进一步扩展此答案,并按照“当任何参数为动态参数时,所有分辨率都推迟到运行时” 添加句子。虽然明显,你这个重要的一点是很难找到其他地方的SO(见stackoverflow.com/questions/48324768例如)
阿列克谢Levenkov

18

因为First()不是方法List。它在Linq Extension中定义为IEnumerable<>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.