If you run TestClass.Test() you will get a RuntimeBinderException. It all starts with var str = DoSomething(obj); implicitly typing to dynamic rather than string. Can someone explain what is happening here? Why does RequiresString(str); work? I understand that you can't call extension methods on dynamic objects, but this whole thing feels a bit dirty and broken to me. It all compiles fine despite obvious type mismatches then fails at runtime.
public static class ExtensionTest
{
public static string ToJsonTest(this object x)
{
return string.Empty;
}
}
public static class TestClass
{
public static void Test()
{
dynamic obj = new ExpandoObject();
obj.var1 = "hello";
var str = DoSomething(obj);
var testObj = RequiresString(str);
var json = testObj.ToJsonTest();
}
public static string DoSomething(object x)
{
return string.Empty;
}
public static TestObj RequiresString(string x)
{
return new TestObj();
}
public class TestObj
{
public int Prop1 { get; set; }
}
}
The call to
RequiresStringcontainsdynamicarguments, so it's resolved at runtime using the actual argument's type. The actual type returned byDoSomethingisstring, so the runtime binder looks forRequiresString(string), which can be successfully found asTestClass.RequiresString. So far, so good.The next call
testObj.ToJsonTest()fails, as you already mentioned, because extension methods ondynamictargets are not resolved, so the next call fails.Yes, it might feel a little bit dirty because there are (almost) no compile-time checks when
dynamics are involved, very much like weakly typed scripting languages. That's why I'd advise usingdynamiconly if really needed and in the narrowest possible context; in particular, I'd saydynamicshould not be seen on class' public surface.