为什么动态重载决策不考虑扩展方法候选?

时间:2012-01-17 17:04:03

标签: c# linq dynamic xelement

[TestFixture]
public class ExpandoToMessageConverterTests
{
/// <summary>
/// CanConvertEvent
/// </summary>
[Test]
public void CanConvertEvent()
{
    dynamic expandoEvent = new ExpandoObject();
    expandoEvent.PropertyOne = "pROPERTYoNE";
    expandoEvent.PropertyTow = "pROPERTYtWO";

    XElement xEvent=ExpandoToMessageConverter.ExpandoToMessageEvent(expandoEvent);

    /*var xEvent = new XElement("event",
                                new XElement("properties",
                                            new XElement("property",
                                                        new XAttribute("name", "pROPERTYoNE"),
                                                        new XAttribute("value", "someVal")),
                                            new XElement("property",
                                                        new XAttribute("name", "pROPERTYtWO"),
                                                        new XAttribute("value", "BLAH"))));*/
    Assert.IsNotNull(xEvent);
    var properties = new List<XElement>(xEvent.Descendants("properties"));
    Assert.AreEqual(1,properties.Count);


    var value = ((IEnumerable)xEvent.XPathEvaluate("properties/property")).Cast<XElement>();
    Assert.AreEqual(2, value.Count());
}

在上面的代码中,我以不同的方式创建相同的xml(一个,显式,被注释掉)。另一个是使用ExpandoToMessageEvent(ExpandoObject),它返回一个XElement。 这对我来说是个谜:

  • 如果我将xEvent声明为var xEvent,则CLR会抱怨未在XElement上定义XPathEvaluate。事实并非如此;它是一种扩展方法。
  • 现在代码片段的方式(即xEvent声明为XElement),它运行正常。
  • 如果我替换以'dynamic'开头的部分,并在调用我的ExpandoToMessageEvent方法结束时结束,而当前注释掉的部分CLR很高兴。

显然,我可以让它发挥作用。但问题是:为什么'动态'一词会让CLR失效?

我决定检查更多的东西,这就是我发现的:如果我将新的ExpandoObject()传递给函数,那么“var xEvent = ExpandoToMessageConverter.ExpandoToMessageEvent(new ExpandoObject())”中的xEvent类型“确定正确,CLR很高兴。但是,如果我说“dynamic blah = new ExpandoObject()”然后“var xEvent = ExpandoToMessageEvent(blah)”,则xEvent的类型未正确确定(我猜)并且CLR似乎没有考虑XElement的扩展方法。

2 个答案:

答案 0 :(得分:9)

动态调用的重载解析不考虑扩展方法。

确定给定呼叫上可用的扩展方法需要知道呼叫站点上有哪些“使用”指令。我们之前没有将此信息保存到呼叫站点的机制;我们没有预算来设计,实施,测试和记录新机制,仍然按时发布C#4。因此,我们削减了该部分的功能。

答案 1 :(得分:2)

看起来编译器在使用var因此抛出错误时无法推断扩展方法。但是,dynamic工作正常,因为动态变量不进行编译时类型检查(reference)。