23

I need to create a heterogeneous List of objects (custom classes). My first thought was to create a List<ISomeMarkerInterface> but I quickly learned that this is not what I want. My next thought was List<dynamic> and this didn't seem to be a bad idea. However, I was doing some research and came across this article about boxing and unboxing and in the example, they're doing basically what I want using List<Object>.

Aside from the fact that dynamic will be evaluated at runtime and Object at compile-time, what is the difference between List<dynamic> and List<Object>? Aren't they essentially the same thing?

Jason
  • 51,583
  • 38
  • 133
  • 185
  • 2
    why do you need to store heterogeneous objects in the same list? Just curious... – Mitch Wheat Apr 30 '12 at 07:28
  • you should look for dynamic vs object , check out this thread, it probably replies your answer http://stackoverflow.com/questions/3442821/dynamic-vs-object-type – Habib Apr 30 '12 at 07:30
  • I have a class where one of the properties is a collection of items relevant to that class that are not the same type, but are relevant as a group. – Jason Apr 30 '12 at 07:40
  • As an aside, can you explain why `ISomeMarkerInterface` was no good? – yamen Apr 30 '12 at 07:51
  • `ISomeMarkerInterface` wasn't any good because (and this may just be me) but I was having problems casting back to the actual object to do anything useful. Since marker interfaces have no properties or methods, it was really hard to use in LINQ lambda expressions :\ – Jason Apr 30 '12 at 07:54
  • 1
    If all you want is easy LINQ, have you looked at Enumerable.OfType() with List? http://msdn.microsoft.com/en-us/library/bb360913.aspx – Tanzelax Apr 30 '12 at 08:09

2 Answers2

27

There are 3 "general" types (although not all are real types) in C#: object, var and dynamic.

Object

An actual type, like any other type, with one special rule: if a type doesn't inherit, it inherits from object. From this, it follows that all types inherit from object, directly or indirectly.

Emphasis: object is a type. An object can be of type object, and the type has its methods, like ToString(). Since everything inherits from object, everything can be upcast into object. When you assign an object to an object reference, you are doing upcasting just like when you assign an Elephant type object to an Animal reference where Elephant inherits from Animal.

SomeType x = new SomeType();
object obj = x;
obj.DoSomething();
  • obj is treated as being of type object at compile time, and will be of type object at runtime (which is logical, since it is an actual type - obj is declared as object so can only be of that type)
  • obj.DoSomething() will cause a compile-time error, as object does not have this method, regardless of whether SomeType has it.

Var

This is not an actual type, it is merely shorthand for "compiler, figure out the type for me based on the right side of the assignment".

SomeType x = new SomeType();
var obj = x;
obj.DoSomething();
  • obj is treated as being of type SomeType at compile time, and will be of type SomeType at runtime, just as if you had written "SomeType" instead of "var".
  • if SomeType has a method DoSomething(), this code will work
  • if SomeType doesn't have the method, the code will cause a compile-time error

Dynamic

This is a type that tells the compiler to disable compile-time type checking on the variable. An object is treated as having the type dynamic at compile-time and run-time.

SomeType x = new SomeType();
dynamic obj = x;
obj.DoSomething();
  • obj is of type dynamic at compile and run time
  • if SomeType has a method DoSomething(), this code will work
  • if SomeType doesn't have the method, the code will compile, but throw an exception at run-time
  • note that dynamic can cause exceptions very easily if used carelessly:

    public void f(dynamic x)
    { 
        x.DoSomething();
    }
    

This will throw an exception if x is of a type that doesn't have the DoSomething method, but it will still be possible to call it and pass any object as the parameter without a compile-time error, causing an error that only shows itself at run-time, and possibly only in specific circumstances - a potential bug. So if you use dynamic in any kind of public interface of a class, you should always manually type-check at runtime using reflection, carefully deal with exceptions, or not do it in the first place.

Note: the object being referred to never changes its type, of course. While obj may be object, the x that it refers to is still SomeType.

svinja
  • 5,495
  • 5
  • 25
  • 43
  • 5
    -1 for saying that `dynamic` is not an actual type (very different from `var` which _isn't_ an actual type, as you correctly say). `dynamic` is most definitely a type in C#, it is even a _static_ type, but an object of type `dynamic` will bypass static type checking. Check out §4.7 of the C# Language Specification or this link (http://msdn.microsoft.com/en-us/library/dd264736.aspx) for more information. – Julian Apr 30 '12 at 08:52
  • Oops, I fixed it. I should have checked first I guess. :D I though dynamic was immediately resolved to the appropriate type on assignment run-time and was never actually typed as "dynamic", but apparently this is not the case. – svinja Apr 30 '12 at 09:03
  • By the way, if you run into the ["missing compiler required member"](https://connect.microsoft.com/VisualStudio/feedback/details/1630573/missing-compiler-required-member-microsoft-csharp-runtimebinder-csharpargumentinfo-create) compiler error, you need to add a reference to `Microsoft.CSharp.dll`. – skst Jun 15 '16 at 01:20
2

The difference is that if you use object and you try to access some member of your object it will be a compile time error (because object doesn't have this member). In order to work you need to know what the type is and cast it.

With dynamic you can access any member - no compile time error. If the member doesn't exist at runtime it would be a runtime error. This is the way to go if you know that your heretogeneous objects all have the same member for example.

However if this is the case there is another more clear solution: You can define an interface, with this member and then make all your heretogeneous objects implement it and your list can be List<IYourInterface>.

Keep in mind that dynamic's performance might be slightly worse, because of the, well, dynamic type resolution.

Petar Ivanov
  • 91,536
  • 11
  • 82
  • 95
  • using dynamic, can you check the existence of a member and continue on if it isn't there without throwing an error? kind of like in javascript how you can do something like `if (data.something) {}`? – Jason Apr 30 '12 at 07:36
  • 1
    This is called reflection. You can use it with or without *dynamic*. Look into GetType(), GetMethod(), etc. – svinja Apr 30 '12 at 08:07
  • +1, if you're going down the reflection route, you might as well just use Object (but I'd still recommend the marker interface on top of that) – MattDavey Apr 30 '12 at 09:09