What is the 'dynamic' type in C# 4.0 used for?
Asked Answered
S

10

278

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

Is there a situation where it can save the day?

Svetlanasvoboda answered 22/4, 2010 at 12:14 Comment(4)
possible duplicate of #2256482Rightness
It's useful when working with COM or dynamically typed languages. For example if you'd use lua or python for scripting your language it's very convenient to just call into the scripting code as if it were normal code.Babblement
possible duplicate of What is the practical use of "dynamic" variable in C# 4.0?Footprint
I hope this article has complete answer to your question visualstudiomagazine.com/Articles/2011/02/01/…Orsay
C
223

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

Compliant answered 22/4, 2010 at 12:20 Comment(9)
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.Grower
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.Grower
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.)Juliannejuliano
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.)Juliannejuliano
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.Enceinte
now all we need is getting pointers outside unsafe and finally we can code C(++) again.Cymose
I know it's archeology, however - your example of working dynamic is fault and second line will give you a RuntimeBinderException.Cavender
I'm not sure whether I have chosen proper approach but the only case I have used dynamic was in MVC for Ajax call. If entity wasn't found by .SingleOrDefault() then it was initialized to false. The only purpose was to reduce amount of data sent to client.Maryrosemarys
To suggest to use dynamic types instead of using double/decimal types it's just wrong. The type was designed to be used when interoping with COM apis or dynamic languages.Eurasian
R
237

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:

Rhythmist answered 22/4, 2010 at 12:48 Comment(5)
It's also useful aside from COM for web JSON APIs where the structure of the de-serialized JSON objects are not specified in C#. For example System.Web.Helpers.Json's Decode method returns a dynamic object.Temple
An aside about "they still regard C# as a strongly typed language": Eric Lippert is not a fan of "strongly typed" as a description.Cranny
I disagree with him, but it's a matter of opinion, not a matter of fact. "Strongly typed" to me means that the compiler knows, at compile time, which type is used, and thus enforces the rules set around those types. The fact that you can opt into a dynamic type that postpones the rule checking and binding to runtime does not, to me, mean that the language is weakly typed. I usually don't contrast strongly typed to weakly typed, however, I usually compare it to dynamically typed, like languages like Python, where everything is a duck until it barks.Rhythmist
What's the point of this answer? Half of it is about optional parameters and the IDispatch interface.Eurasian
That is why dynamic was added, to support other ecosystems for how reflection-like method invocation can be done, as well as provide a sort of black box approach to data structures with a documented way of achieving this.Rhythmist
C
223

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

Compliant answered 22/4, 2010 at 12:20 Comment(9)
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.Grower
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.Grower
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.)Juliannejuliano
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.)Juliannejuliano
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.Enceinte
now all we need is getting pointers outside unsafe and finally we can code C(++) again.Cymose
I know it's archeology, however - your example of working dynamic is fault and second line will give you a RuntimeBinderException.Cavender
I'm not sure whether I have chosen proper approach but the only case I have used dynamic was in MVC for Ajax call. If entity wasn't found by .SingleOrDefault() then it was initialized to false. The only purpose was to reduce amount of data sent to client.Maryrosemarys
To suggest to use dynamic types instead of using double/decimal types it's just wrong. The type was designed to be used when interoping with COM apis or dynamic languages.Eurasian
R
34

I am surprised that nobody mentioned multiple dispatch. The usual way to work around this is via Visitor pattern and that is not always possible so you end up with stacked is checks.

So here is a real life example of an application of my own. Instead of doing:

public static MapDtoBase CreateDto(ChartItem item)
{
    if (item is ElevationPoint) return CreateDtoImpl((ElevationPoint)item);
    if (item is MapPoint) return CreateDtoImpl((MapPoint)item);
    if (item is MapPolyline) return CreateDtoImpl((MapPolyline)item);
    //other subtypes follow
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

You do:

public static MapDtoBase CreateDto(ChartItem item)
{
    return CreateDtoImpl(item as dynamic);
}

private static MapDtoBase CreateDtoImpl(ChartItem item)
{
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

private static MapDtoBase CreateDtoImpl(MapPoint item)
{
    return new MapPointDto(item);
}

private static MapDtoBase CreateDtoImpl(ElevationPoint item)
{
    return new ElevationDto(item);
}

Note that in first case ElevationPoint is subclass of MapPoint and if it's not placed before MapPointit will never be reached. This is not the case with dynamic, as the closest matching method will be called.

As you might guess from the code, that feature came handy while I was performing translation from ChartItem objects to their serializable versions. I didn't want to pollute my code with visitors and I didn't want also to pollute my ChartItem objects with useless serialization specific attributes.

Romans answered 15/11, 2016 at 20:2 Comment(7)
Didn't know about this use case. A bit hacky at best, though. It'll throw any static analyser off.Harber
@Harber that is true, but I wouldn't call it a hack. Static analysis is good, but I wouldn't let it prevent me from an elegant solution, where the alternatives are: open-closed principle violation (Visitor pattern) or increased cyclomatic complexity with dreaded is stacked one on top of the other.Romans
Well you have the option of pattern matching with C# 7, no?Harber
Well is operators are a lot less expensive that way (avoiding double cast) and you get static analysis back ;-) and performance.Harber
@idbrii please don't change my answers. Feel free to drop a comment and I will clarify (if needed) as I'm still active in this community. Also, please don't use magic; there is no such thing as magic.Romans
@SteliosAdamantidis: I modified to clarify points I found unclear. If you prefer: Isn't the visitor pattern already using multiple dispatches; how does this differ? What part of the second code block makes it "multiple dispatch"?Sargeant
Reading both @angry person's answer and this one, I feel that this CAN be described to be compatible with the first one: when we have to interoperate with types that weren't fully architected in excellent C# manner, we need dynamic. For the other answer, that's because they come from a foreign lang; for this answer, it's because they come from an API/source we don't control. But - in a way - both are solving the same problem. (I was directed here b/c I'm interfacing with a bad 15-years old C# API that can't be re-architected - too much legacy code! - and dynamic is a huge help)Venuti
G
12

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:

For example, you might use the following code to increment a counter in XML in C#.

Scriptobj.SetProperty("Count", ((int)GetProperty("Count")) + 1);

By using the DLR, you could use the following code instead for the same operation.

scriptobj.Count += 1;

MSDN lists these advantages:

  • Simplifies Porting Dynamic Languages to the .NET Framework
  • Enables Dynamic Features in Statically Typed Languages
  • Provides Future Benefits of the DLR and .NET Framework
  • Enables Sharing of Libraries and Objects
  • Provides Fast Dynamic Dispatch and Invocation

See MSDN for more details.

Grower answered 22/4, 2010 at 12:21 Comment(4)
And the change tot he VM required for dynamic actually makes dynamic languages easier.Itinerate
@Dykam: There is no change to the VM. The DLR works just fine all the way back to .NET 2.0.Rightness
@Jörg, yes there is a change. The DLR is partly rewritten because it now the VM has build in support for dynamic resolvement.Itinerate
I was a bit too optimistic, research showed changes were not that big.Itinerate
J
7

An example of use :

You consume many classes that have a common property 'CreationDate' :

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }        
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

If you write a common method that retrieves the value of the 'CreationDate' property, you'd have to use reflection:

static DateTime RetrieveValueOfCreationDate(Object item)
{
    return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
}

With the 'dynamic' concept, your code is much more elegant :

static DateTime RetrieveValueOfCreationDate(dynamic item)
{
    return item.CreationDate;
}
Jesusitajet answered 9/4, 2017 at 18:32 Comment(1)
Duck typing, nice. However you should use an interface for this if those are your types.Harber
A
3

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

Anschauung answered 22/4, 2010 at 12:16 Comment(0)
Y
3

The best use case of dynamic type variables for me was when, recently, I was writing a data access layer in ADO.NET (using SQLDataReader) and the code was invoking the already written legacy stored procedures. There are hundreds of those legacy stored procedures containing bulk of the business logic. My data access layer needed to return some sort of structured data to the business logic layer, C# based, to do some manipulations (although there are almost none). Every stored procedure returns different set of data (table columns). So instead of creating dozens of classes or structs to hold the returned data and pass it to the BLL, I wrote the below code which looks quite elegant and neat.

public static dynamic GetSomeData(ParameterDTO dto)
        {
            dynamic result = null;
            string SPName = "a_legacy_stored_procedure";
            using (SqlConnection connection = new SqlConnection("my connection string"))
            {
                SqlCommand command = new SqlCommand(SPName, connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;                
                command.Parameters.Add(new SqlParameter("@empid", dto.EmpID));
                command.Parameters.Add(new SqlParameter("@deptid", dto.DeptID));
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        dynamic row = new ExpandoObject();
                        row.EmpName = reader["EmpFullName"].ToString();
                        row.DeptName = reader["DeptName"].ToString();
                        row.AnotherColumn = reader["AnotherColumn"].ToString();                        
                        result = row;
                    }
                }
            }
            return result;
        }
Yasukoyataghan answered 28/3, 2018 at 6:50 Comment(2)
Was there a downside to doing this? I run into the same problem and thought it was absurd to write a class to represent every query result. The DB tables are likely not going to change so I use classes for inserts updates & deletes. Select queries are too broad to write a class or translate for each of themSeptempartite
Back then, I did not notice any downside. I would have probably but I got moved to another project.Yasukoyataghan
U
1
  1. You can call into dynamic languages such as CPython using pythonnet:

dynamic np = Py.Import("numpy")

  1. You can cast generics to dynamic when applying numerical operators on them. This provides type safety and avoids limitations of generics. This is in essence *duck typing:

T y = x * (dynamic)x, where typeof(x) is T

User answered 4/3, 2016 at 3:26 Comment(0)
L
1

Another use case for dynamic typing is for virtual methods that experience a problem with covariance or contravariance. One such example is the infamous Clone method that returns an object of the same type as the object it is called on. This problem is not completely solved with a dynamic return because it bypasses static type checking, but at least you don't need to use ugly casts all the time as per when using plain object. Otherwise to say, the casts become implicit.

public class A
{
    // attributes and constructor here
    public virtual dynamic Clone()
    {
        var clone = new A();
        // Do more cloning stuff here
        return clone;
    }
}

public class B : A
{
    // more attributes and constructor here
    public override dynamic Clone()
    {
        var clone = new B();    
        // Do more cloning stuff here
        return clone;
    }
}    

public class Program
{
    public static void Main()
    {
        A a = new A().Clone();  // No cast needed here
        B b = new B().Clone();  // and here
        // do more stuff with a and b
    }
}
Louvenialouver answered 28/2, 2019 at 13:18 Comment(0)
W
0

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; it i s beneficial, but I heard a lot goes on under the scenes in terms of generated IL and that can come at a performance price.

Wesle answered 22/4, 2010 at 12:16 Comment(4)
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.Rhythmist
Sure, but that would have been "legit" with "object" instead of "dynamic". You haven't shown anything interesting about dynamic here.Juliannejuliano
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.Wesle
Last resort use case is not explainedUser

© 2022 - 2024 — McMap. All rights reserved.