views:

429

answers:

7

C# 4.0 introduced a new type called 'dynamic'. It all sounds good but what would a programmer use it for?

If anyone can think of a situation where it can save the day please tell me.

+1  A: 

COM interop. Especially IUnknown. It was designed specially for it.

Aen Sidhe
+2  A: 

Hey,

It evaluates at runtime, so you can switch the type like you can in JavaScript to whatever you want. This is legit:

dynamic i = 12;
i = "text";

And so you can change the type as you need. Use it as a last resort, beneficial, but I heard a lot goes on under the scenes in terms of generated IL.

Brian
I would be hesitant to say that it is "legit". It will surely compile, so as such it is "legit code" in the sense that the compiler will now compile it, and the runtime will run it. But I would never want to see that particular piece of code (or something resembling it) in any of the code I maintain, or it would be a near-firing offense.
Lasse V. Karlsen
Sure, but that would have been "legit" with "object" instead of "dynamic". You haven't shown anything interesting about dynamic here.
Eric Lippert
For object, you would have to cast it to the appropriate type, in order to actually invoke any of its methods... you lose the signature; you can have your code call any method without compile error, and it errors at runtime. Was in a hurry to type out, sorry for not specifying. And @Lasse, I would agree and I probably won't use dynamic much.
Brian
+5  A: 

The dynamic keyword is new to C# 4.0, and is used to tell the compiler that a variable's type can change or that it is not known until runtime. Think of it as being able to interact with an Object without having to cast it.

dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!

Notice we did not need to cast nor declare cust as type Customer. Because we declared it dynamic, the runtime takes over and then searches and sets the FirstName property for us. Now, of course, when you are using a dynamic variable, you are giving up compiler type checking. This means the call cust.MissingMethod() will compile and not fail until runtime. The result of this operation is a RuntimeBinderException because MissingMethod is not defined on the Customer class.

The example above shows how dynamic works when calling methods and properties. Another powerful (and potentially dangerous) feature is being able to reuse variables for different types of data. I'm sure the Python, Ruby, and Perl programmers out there can think of a million ways to take advantage of this, but I've been using C# so long that it just feels "wrong" to me.

dynamic foo = 123;
foo = "bar";

OK, so you most likely will not be writing code like the above very often. There may be times, however, when variable reuse can come in handy or clean up a dirty piece of legacy code. One simple case I run into often is constantly having to cast between decimal and double.

decimal foo = GetDecimalValue();
foo = foo / 2.5; // Does not compile
foo = Math.Sqrt(foo); // Does not compile
string bar = foo.ToString("c");

The second line does not compile because 2.5 is typed as a double and line 3 does not compile because Math.Sqrt expects a double. Obviously, all you have to do is cast and/or change your variable type, but there may be situations where dynamic makes sense to use.

dynamic foo = GetDecimalValue(); // still returns a decimal
foo = foo / 2.5; // The runtime takes care of this for us
foo = Math.Sqrt(foo); // Again, the DLR works its magic
string bar = foo.ToString("c");

Read more feature : http://www.codeproject.com/KB/cs/CSharp4Features.aspx

Pranay Rana
Personally I dont like the thought of using the `dynamic` in c# for solving problems that can be solved (maybe even better) by standard c# features and static typing, or at most with type inference (`var`). `dynamic` should *only* be used when it comes to interoperabilty issues with the DLR. If you write code in a static typed language, like c# is, then do it, and dont emulate a dynamic language. Thats just ugly.
Philip Daubmeier
If you make heavy use of `dynamic` variables in your code where you dont need them (like in your example with the squareroot) you give up clean compile time error checking; instead you are now getting possible runtime errors.
Philip Daubmeier
Mostly fine, but a couple minor errors. First, it is not correct to say that dynamic means the *variable's* type can change. The variable in question is of type "dynamic" (from the perspective of the C# language; from the CLR's perspective the variable is of type object). The type of a variable *never* changes. The runtime type of the *value* of a variable can be any type compatible with the type of the variable. (Or in the case of reference types, it can be null.)
Eric Lippert
Regarding your second point: C# already had the feature of "make a variable you can put anything into" -- you can always make a variable of type object. The interesting thing about dynamic is what you point out in your first paragraph: dynamic is nigh-identical to object, except that the semantic analysis is deferred until runtime, and the semantic analysis is done on the runtime type of the expression. (Mostly. There are some exceptions.)
Eric Lippert
I've spent a downvote point on this, principally because it is implicitly advocating the use of the keyword for general use. It has a specifically-targeted purpose (described perfectly in Lasses' answer) and although this answer is -technically- correct, it is likely to lead developers astray.
Jonners
+6  A: 

It makes it easier for static typed languages (CLR) to interoperate with dynamic ones (python, ruby ...) running on the DLR (dynamic language runtime), see MSDN.

Philip Daubmeier
And the change tot he VM required for dynamic actually makes dynamic languages easier.
Dykam
@Dykam: There is no change to the VM. The DLR works just fine all the way back to .NET 2.0.
Jörg W Mittag
@Jörg, yes there is a change. The DLR is partly rewritten because it now the VM has build in support for dynamic resolvement.
Dykam
I was a bit too optimistic, research showed changes were not that big.
Dykam
+7  A: 

I wrote an article about dynamics on the code project here:

http://www.codeproject.com/KB/cs/TheDynamicKeyword.aspx

Keith Paul Barrow
+1 For the well written article, and for the concluding sentence: "The great danger lies in the use of dynamic objects in inappropriate contexts, such as in statically typed system, or worse, in place of an interface/base class in a properly typed system."
Philip Daubmeier
Hi Keith,it's indeed a really good article.Just one factual error. IDynamicObject was renamed to IDynamicMetaObjectProvider (after Beta1, I think.) There is no "IDynamicObject" in .NET 4.0.
Alexandra Rusina
@Alexandra Rusina, Thanks, this was written with the Beta1 , I'll fix the article!
Keith Paul Barrow
+20  A: 

The dynamic keyword was added, together with many other new features of C# 4.0, to make it simpler to talk to code that lives in or comes from other runtimes, that has different APIs.

Take an example.

If you have a COM object, like the Word.Application object, and want to open a document, the method to do that comes with no less than 15 parameters, most of which are optional.

To call this method, you would need something like this (I'm simplifying, this is not actual code):

object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing);

Note all those arguments? You need to pass those since C# before version 4.0 did not have a notion of optional arguments. In C# 4.0, COM APIs have been made easier to work with by introducing:

  1. Optional arguments
  2. Making ref optional for COM APIs
  3. Named arguments

The new syntax for the above call would be:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

See how much easier it looks, how much more readable it becomes?

Let's break that apart:

                                    named argument, can skip the rest
                                                   |
                                                   v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
                                 ^                         ^
                                 |                         |
                               notice no ref keyword, can pass
                               actual parameter values instead

The magic is that the C# compiler will now inject the necessary code, and work with new classes in the runtime, to do almost the exact same thing that you did before, but the syntax has been hidden from you, now you can focus on the what, and not so much on the how. Anders Hejlsberg is fond of saying that you have to invoke different "incantations", which is a sort of pun on the magic of the whole thing, where you typically have to wave your hand(s) and say some magic words in the right order to get a certain type of spell going. The old API way of talking to COM objects was a lot of that, you needed to jump through a lot of hoops in order to coax the compiler to compile the code for you.

Things break down in C# before version 4.0 even more if you try to talk to a COM object that you don't have an interface or class for, all you have is an IDispatch reference.

If you don't know what it is, IDispatch is basically reflection for COM objects. With an IDispatch interface you can ask the object "what is the id number for the method known as Save", and build up arrays of a certain type containing the argument values, and finally call an Invoke method on the IDispatch interface to call the method, passing all the information you've managed to scrounge together.

The above Save method could look like this (this is definitely not the right code):

string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);

All this for just opening a document.

VB had optional arguments and support for most of this out of the box a long time ago, so this C# code:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

is basically just C# catching up to VB in terms of expressiveness, but doing it the right way, by making it extendable, and not just for COM. Of course this is also available for VB.NET or any other language built on top of the .NET runtime.

You can find more information about the IDispatch interface on Wikipedia: IDispatch if you want to read more about it. It's really gory stuff.

However, what if you wanted to talk to a Python object? There's a different API for that than the one used for COM objects, and since Python objects are dynamic in nature as well, you need to resort to reflection magic to find the right methods to call, their parameters, etc. but not the .NET reflection, something written for Python, pretty much like the IDispatch code above, just altogether different.

And for Ruby? A different API still.

JavaScript? Same deal, different API for that as well.

The dynamic keyword consists of two things:

  1. The new keyword in C#, dynamic
  2. A set of runtime classes that knows how to deal with the different types of objects, that implement a specific API that the dynamic keyword requires, and maps the calls to the right way of doing things. The API is even documented, so if you have objects that comes from a runtime not covered, you can add it.

The dynamic keyword is not, however, meant to replace any existing .NET-only code. Sure, you can do it, but it was not added for that reason, and the authors of the C# programming language with Anders Hejlsberg in the front, has been most adamant that they still regard C# as a strongly typed language, and will not sacrifice that principle.

This means that although you can write code like this:

dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;

and have it compile, it was not meant as a sort of magic-lets-figure-out-what-you-meant-at-runtime type of system.

The whole purpose was to make it easier to talk to other types of objects.

There's plenty of material on the internet about the keyword, proponents, opponents, discussions, rants, praise, etc.

I suggest you start with the following links and then google for more:

Lasse V. Karlsen
+1 *That* is what `dynamic` is for. Thanks.
Philip Daubmeier
+1 Awesome answer.
Jonners
A: 

It will mostly be used by RAD and python victims to destroy code quality, Intellisense and compile time bug detection.

stormianrootsolver