Search code examples
c#linqdynamicxelement

Why does dynamic overload resolution not consider extension method candidates?


[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());
}

In the code above I create the same xml in different ways (one, explicit, is commented out). The other one is using the ExpandoToMessageEvent(ExpandoObject), which returns a XElement. Here is the mystery for me:

  • if I declare xEvent as var xEvent the CLR complains that XPathEvaluate is not defined on XElement. It is not, indeed; its an extension method.
  • the way the snippet is now (i.e. xEvent declared as XElement), it works fine.
  • if I replace the section starting with 'dynamic' and ending at the end of the call to my ExpandoToMessageEvent method with the section that is currently commented out CLR is happy.

Obviously, I can make it work. But the question is: why does 'dynamic' word throw CLR off?

I decided to check a couple more things and here is what I found: If i pass a new ExpandoObject() to the function then the type of xEvent in the "var xEvent = ExpandoToMessageConverter.ExpandoToMessageEvent(new ExpandoObject())" is determined correctly and CLR is happy. However, if I say "dynamic blah = new ExpandoObject()" and then " var xEvent=ExpandoToMessageEvent(blah)", the type of xEvent is not determined correctly (I guess) and CLR does not seem to consider extension methods for XElement.


Solution

  • Overload resolution of a dynamic invocations does not consider extension methods.

    Determining what extension methods are available on a given call requires knowing what "using" directives were in force at the call site. We had no previously existing mechanism for persisting this information into the call site; we did not have the budget to design, implement, test and document a new mechanism and still ship C# 4 on time. We therefore cut that portion of the feature.