C# Dynamic Keyword — Run-time penalty?
Does defining an instance as dynamic in C# mean:
The compiler does not perform compile-time type checking, but run-time checking takes place like it always does for all instances.
The compiler does not perform compile-time type checking, but run-time checking takes place, unlike with any other non-dynamic instances.
Same as 2, and this comes with performance penalty (trivial? potentially significant?).
Solution 1:
The question is very confusing.
Does defining an instance as dynamic in C# mean:
By "defining an instance" do you mean "declaring a variable"?
The compiler does not perform compile-time type checking, but run-time checking takes place like it always does for all instances.
What do you mean by "run-time checking like it always does"? What run-time checking did you have in mind? Are you thinking of the checking performed by the IL verifier, or are you thinking of runtime type checks caused by casts, or what?
Perhaps it would be best to simply explain what "dynamic" does.
First off, dynamic is from the perspective of the compiler a type. From the perspective of the CLR, there is no such thing as dynamic; by the time the code actually runs, all instances of "dynamic" have been replaced with "object" in the generated code.
The compiler treats expressions of type dynamic exactly as expressions of type object, except that all operations on the value of that expression are analyzed, compiled and executed at runtime based on the runtime type of the instance. The goal is that the code executed has the same semantics as if the compiler had known the runtime types at compile time.
Your question seems to be about performance.
The best way to answer performance questions is to try it and find out - what you should do if you need hard numbers is to write the code both ways, using dynamic and using known types, and then get out a stopwatch and compare the timings. That's the only way to know.
However, let's consider the performance implications of some operations at an abstract level. Suppose you have:
int x = 123;
int y = 456;
int z = x + y;
Adding two integers takes about a billionth of a second on most hardware these days.
What happens if we make it dynamic?
dynamic x = 123;
dynamic y = 456;
dynamic z = x + y;
Now what does this do at runtime? This boxes 123 and 456 into objects, which allocates memory on the heap and does some copies.
Then it starts up the DLR and asks the DLR "has this code site been compiled once already with the types for x and y being int and int?"
The answer in this case is no. The DLR then starts up a special version of the C# compiler which analyzes the addition expression, performs overload resolution, and spits out an expression tree describing the lambda which adds together two ints. The DLR then compiles that lambda into dynamically generated IL, which the jit compiler then jits. The DLR then caches that compiled state so that the second time you ask, the compiler doesn't have to do all that work over again.
That takes longer than a nanosecond. It takes potentially many thousands of nanoseconds.
Does that answer your questions? I don't really understand what you're asking here but I'm making a best guess.
Solution 2:
As far as I know, the answer is 3.
You can do this:
dynamic x = GetMysteriousObject();
x.DoLaundry();
Since the compiler does no type checking on x
, it will compile this code, the assumption being that you know what you're doing.
But this means extra run-time checking has to occur: namely, examining x
's type, seeing if it has a DoLaundry
method accepting no arguments, and executing it.
In other words the above code is sort of like doing this (I'm not saying it's the same, just drawing a comparison):
object x = GetMysteriousObject();
MethodInfo doLaundry = x.GetType().GetMethod(
"DoLaundry",
BindingFlags.Instance | BindingFlags.Public
);
doLaundry.Invoke(x, null);
This is definitely not trivial, though that isn't to say you're going to be able to see a performance issue with your naked eye.
I believe the implementation of dynamic
involves some pretty sweet behind-the-scenes caching that gets done for you, so that if you run this code again and x
is the same type, it'll run a lot faster.
Don't hold me to that, though. I don't have all that much experience with dynamic
; this is merely how I understand it to work.
Solution 3:
Declaring a variable as dynamic is similar to declaring it as object. Dynamic simply gets another flag indicating that member resolution gets deferred to run-time.
In terms of the performance penalty - it depends on what the underlying object is. That's the whole point of dynamic objects right? The underlying object can be a Ruby or Python object or it can be a C# object. The DLR will figure out at run-time how to resolve member calls on this object and this resolution method will determine the performance penalty.
Having said that - there definitely is a performance penalty.
That's why we're not simply going to start using dynamic objects all over the place.