C# dynamic is evil, not your friend

Last year I wrote a blog post on an issue I faced with C# dynamic, where my one small mistake killed the IIS worker process, w3wp.exe. Recently, ignoring my own advice, I used C# dynamic at one of the places in my code. Not surprisingly found another interesting issue.

Show me the code!

Here is the minimal reproducible example of the issue:

class Program
{
public static void Main()
{
dynamic data = new { SomeProperty = "ABC" };
var response = IsTrue(data);
if (response == "1")
{
Console.WriteLine("How can this compile?");
}
}
private static bool IsTrue(object someData)
{
return true;
}
}
view raw Program.cs hosted with ❤ by GitHub

The issue

As you can see in the above code, method IsTrue returns a bool, but I’m still able to assign it to a string type. This code compiles successfully. At the runtime, however, it throws below exception:

Unhandled exception. CSharp.RuntimeBinder.RuntimeBinderException: Operator ‘==’ cannot be applied to operands of type ‘bool’ and ‘string’  … at CallSite.Target(Closure , CallSite , Object , String ) … at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)

At first glance, it just does not make sense. How can a return type of a static method not inferred by C# compiler? I reached out to the community on StackOverflow and Twitter to understand this little bit more.

Here is the response, I received from Jon Skeet:

When you call a method with an argument of type dynamic, the call is dynamically bound – so the compiler treats the return type as dynamic too.

There are some cases where the compiler will notice things that aren’t feasible, but generally when you use dynamic you lose a lot of compile-time type safety. I’m slightly surprised by the exact exception you received (and it’s not the exception I see) , but I’m not surprised that it compiled.

David Fowler on twitter also explained that dynamic turns the method call into a late-bound call. 

I also did a little bit reading and came across this Microsoft documentation where it explains that overload resolution for dynamic occurs at runtime instead of compile-time. However, this issue proved that the behavior is not limited to method overload alone.

Final Words

The root cause of the issue which I came across here is no different to the last timedynamic is not static :). C# dynamic defers the resolution and the problems that come along with it to the runtime.

The issue, yet again, proves why dynamic is terrible and how it can turn an innocent-looking code into a production nightmare. 

Don Syme, the F# language designer, has this to say about dynamic and I could not agree more.

Posted In

, ,