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 RequiresString
contains dynamic
arguments, so it's resolved at runtime using the actual argument's type. The actual type returned by DoSomething
is string
, so the runtime binder looks for RequiresString(string)
, which can be successfully found as TestClass.RequiresString
. So far, so good.
The next call testObj.ToJsonTest()
fails, as you already mentioned, because extension methods on dynamic
targets 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 dynamic
s are involved, very much like weakly typed scripting languages. That's why I'd advise using dynamic
only if really needed and in the narrowest possible context; in particular, I'd say dynamic
should not be seen on class' public surface.