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;
}
}
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 stringtype. 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 inferredby C# compiler? I reached out to the community on StackOverflow and Twitterto 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.
Dynamic infects the entire callsite turning everything into a late bound call
— David Fowler (@davidfowl) September 7, 2020
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 time. dynamic 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.
– no expression form for generative list or sequence expressions (making HTML DSLs a mess among other things)
— Don Syme (@dsymetweets) August 14, 2020
– dynamic is hell waiting to destroy your life
1 comment
Comments were carried over from the previous site and are closed.
Bobo ·
Dynamic’s best use is in a closed environment when you know roughly what the generic class of it is, and what the outputs and functions of the dynamic variable should be. Dynamic used well is far from evil.