List<Object> vs List<dynamic> - c#

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?

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.

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.

Related

C# how to cast object to runtime type?

How can I cast (or convert, if cast not possible or reasonable) an object into its runtime type? I can get runtimeType using reflection, but can't figure out how to get List<string> using property.GetValue - I know that I could explicitly do as List<String> but this is for a sort-of soft-code engine where the types are not known until runtime.
Any help is appreciated - thanks! (but looking for code solutions please, not "you shouldn't do it this way..." answers)
// trimmed-down example class
class Bus { public List<string> Passengers {get;set;} }
// create new instance of class
var obj = new Bus();
// get property value using reflection
var listPropertyName = "Passengers";
var property = GetType(obj).GetProperty($"{listPropertyName}");
var runtimeType = property.PropertyType;
// returns object, but I want List<string> instead
// (or whatever it is; could be different types like T, List<T>, etc.)
var val = property.GetValue(obj);
// doesn't work (assigns null), expects compile-time type
var val = property.GetValue(obj) as runtimeType;
TL;DR
You can't cast something to an unknown type specified at runtime. That would mean that within your code, you don't know what the object's properties or methods are unless you use even more reflection. In that case what would be the point of casting it?
Sometimes we deal with types that aren't known until runtime. But unless the type really doesn't matter at all, the object is useless unless we can cast it to some predetermined type that is specified in our code, not at runtime.
In this line of code:
var val = property.GetValue(obj);
the declared type of val is inferred by the compiler. That type is object because that's the type that GetValue returns. The actual type of the object could be string, int, List<Foo>, whatever. But you've got a variable val of type object.
If you could do this:
var val = property.GetValue(obj) as runtimeType;
Then what would the compile-time type of val be? How can it have any, since runTimeType is a runtime value? The object is useless unless you can call methods or inspect its properties. But you can't do that without knowing the type, unless you use more reflection. But if your're going to do that then there's no point in casting it.
Somewhere downstream from the code you've posted you'll presumably want to actually do something with the object that involves its methods or properties. That means knowing what type you think it is and casting it as that type. That would be a type specified in your code, not something determined at runtime.
For example:
var val = property.GetValue(obj); // I know this is a string
var myString = (string)val;
var findX = myString.IndexOf("X");
I think it's a string so I cast it as a string. (There could be additional checks in there.) Now that I've cast it, I've got a variable that's declared as type string, and I can use it as a string. (Unless it wasn't a string - then it will throw a runtime exception.)
That's the benefit of casting - it allows us to assign something to a strongly-typed variable with a type we specify and then use it accordingly. Casting to an unknown type wouldn't benefit us.
At the risk of adding confusion: Someone could say that generics represent types unspecified at runtime, but that's not exactly true. List<T> doesn't specify what T is, but if you create a List<T>, somehow, somewhere you're going to specify the type in your code. In the vast majority of normal scenarios we have to know something about the type of an object or else the object is useless to us.

Object type is same as type in inherited class [duplicate]

C# newbie question here. The following code (taken from the book "C# From Novice to Professional" by Christian Gross, Apress) gives an error:
worksheet.Add("C3", CellFactories.DoAdd(worksheet["A2"], worksheet["B1"]));
The reason is that the method DoAdd() does not accept the given arguments.
public static Func<object> DoAdd(Func<object> cell1, Func<object> cell2) {...}
VS claims that both args in the method call above are of type object whereas the method accepts only Func<object>. But the value of both worksheet elements is of type Func<object>:
worksheet.Add("A2", CellFactories.Static(10.0));
where this Static method just returns the given value:
public static Func<object> Static(object value) { return () => value; }
// return type= Func<object>
When I cast worksheet["A2"] as Func<object>, the code does work.
But there is something I don't understand. The type of the object instance is Func<object>. I have used the GetType() method to see proof of this, and compare the object types of the original elements to that of the cast object (which IS accepted):
Console.Writeline(worksheet["A2"].GetType());
// now cast to the correct type (why can't it do that implicitly, btw?)
Funk1 = worksheet["A2"] as Func<object>;
Console.Writeline(Funk1.GetType());
.. and they are ALL identical! (Type = System.Func'1[System.Object])
And even when I use the .Equals() method to compare both types, it returns true.
Yet, VS sees the first object instance as type object in the method call. Why? Why does the called method 'see' the argument as a different type than the GetType() returns?
(and if so, what good is the GetType() method?)
Thanks a lot for your advice/comments! (It's kinda hard to learn the language if the book examples give an error and you don't see the reason - hence, got the vague impression that something is wrong either with GetType() or VS.)
You need to understand the difference between dynamic typing and static typing. The indexer for your worksheet object most likely has a static type of object.
public object this[string cell]{get{...}set{...}}
Because all objects in C# inherit from type object, the object reference stored in a cell can be a reference to any object.
That is, because a delegate (such as Func<T>) is an object, it can be stored in an object reference:
Func<object> func = ()=>return "foo";
object o = func; // this compiles fine
And the compiler can figure this all out, because it understands implicitly that a derived class can be stored in a reference to a base class.
What the compiler cannot do automatically, is determine what the dynamic type, or run time type of an object is.
Func<object> func = ()=>return "foo";
object o = func; // this compiles fine
func = o; // <-- ERROR
The compiler doesn't know that the object stored in o is actually of type Func<object>. It's not supposed to keep track of this. This is information that must be checked at run time.
func = (Func<object>)o; // ok!
The above line of code compiles into something that behaves similarly to this:
if(o == null)
func = null;
else if(typeof(Func<object>).IsAssignableFrom(func.GetType()))
__copy_reference_address__(func, o); // made up function! demonstration only
else throw new InvalidCastException();
In this way, any cast (conversion from one type to another) can be checked at run time to make sure it's valid and safe.
Others have given accurate and detailed answers, but here I will try to explain in simple language.
When you write worksheet["A2"] you really are calling a member function of worksheet
worksheet has a member function named [] that accepts a string and returns an object
The signature of the member function [] looks like object this[string id]
So the function worksheet["A2"] returns something that is an object. It could be an int or a string or many other things. All the compiler knows is that it will be an object.
In the example, you have it returning a Func<object>. This is fine, because Func<object> is an object. However, you then pass the result of that function in as a parameter to another function.
The problem here is that the compiler only knows that worksheet["A2"] returns an object. That is as specific as the compiler can be.
So the compiler sees that worksheet["A2"] is an object, and you are trying to pass the object to a function that does not accept object as a parameter.
So here you have to tell the compiler "hey dummy, that's a Func<object>" by casting the returned object to the correct type.
worksheet.Add("C3", CellFactories.DoAdd(worksheet["A2"], worksheet["B1"]));
can be re-written as
worksheet.Add("C3", CellFactories.DoAdd((Func<object>)worksheet["A2"], (Func<object>)worksheet["B1"]));
Now the compiler knows that, even though the [] function returns an object, it can treat it like a Func<object>.
side note: You're probably doing too much on one line. That may be hard for people to read in the future.
Why does the called method 'see' the argument as a different type than the GetType() returns?
The compiler only knows that worksheet[] returns an object. The compiler can not call GetType() on it at compile time.
What good is the GetType() method?
There are quite a few uses and abuses of the GetType() method, but that is an entirely different discussion. ;)
In summary, the compiler does not assume anything about types. This is a good thing because you get a compile time error when you try to fit this square peg into a round hole. If the compiler did not complain, this error would surface at run-time, which means you would probably need a unit test to detect the problem.
You can get around this problem by telling the compiler "I know for a fact that this thing is a round peg, trust me." and then it will compile.
If you lie to the compiler, you will get a run-time error when that code is executed.
This is called "static typing". The opposing philosophy is called "dynamic typing" where type checks are done at run-time. Static vs dynamic is a lengthy debate and you should probably research it on your own if you're interested.
VS claims that both args in the method call above are of type object whereas the method accepts only Func. But the value of both worksheet elements is of type Func
Yes, but the declared type is object. The compiler can't know that the actual runtime type will be Func<object>, so an explicit cast is necessary.

Is dynamic is same as Object

In "CLR via C#" book it's mentioned that dynamic keyword corresponding FCL type is System.Object. please clarify this .
It's not the same thing from the C#'s point of view at all... but in the compiled code, a variable declared as type dynamic will usually (possibly always) correspond with a CLR field or local variable of type object.
The C# compiler is responsible for making sure that any source code using that value has the dynamic behaviour applied to it. object is simply the compiler the representation uses for storage. It also applies the [Dynamic] attribute where appropriate, so that other code knows it's to be treated dynamically.
For example, consider this:
public class Foo
{
public dynamic someField;
}
I believe that will be compiled into IL equivalent to:
public class Foo
{
[Dynamic]
public object someField;
}
now if you write:
Foo foo = new Foo();
foo.someField = "hello";
Console.WriteLine(foo.someField.Length);
the compiler uses the attribute to know that foo.someField is dynamic, so the Length property should be dynamically bound.
From MSDN:
The type is a static type, but an object of type dynamic bypasses static type checking. In most cases, it functions like it has type object.
And:
Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.
(emphasis mine)
Since a dynamic reference needs to be able to take any type, it is in effect of the type object (or at least to all appearances and uses), but the compiler will not perform certain type checks on it.

Generic type casting

If i have a type and an object eg.:
- Type someType (coming from somewhere, could be any class eg. MyClass.GetType())
- Object someObject (eg. List<MyClass>())
and want to cast the object back to List<MyClass>. How should i do this?
You can't do this. Generics ensure compile-time safety. You cannot have compile time safety because you know the actual type only at runtime.
You have a runtime type and you want to perform a compile time cast. This is not possible. It is also not clear why you would want to do this in the first place. If you are interested in cases that require reflection, perhaps you should investigate that topic further.
There is no way to have compile-time typing a variable when you only receive the Type information at runtime.
This is different from generics since in generics you get the type information at compile time:
void MyFunc<T>(T thing)
{
// T is passed in at compile time
}
In your case you are getting the type at runtime. So while you can't cast the member to the type the way you normally would you can reflect on the instance and call its members:
void MyFunc(object thing, Type type)
{
var res = t.GetMethod("Add").Invoke(a, new []{"someArg"});
}
Casting means explicitly specifying the type you want to convert to. Since you don't know what your type is, you can't cast to it.
That doesn't mean you can't access the list. If you know the object you have is a list of something, you can cast it to the non-generic IList interface, which provides most of the methods and properties you need:
object obj = GetMyList();
IList list = (IList)obj;
object fifthItem = list[4];
list.RemoveAt(list.Count - 1);
If you describe the problem you're trying to solve rather than the solution you are trying to achieve, then more fitting solutions might be posted.
If you are trying to cast a runtime type at compile time, it is impossible as may said before me.
However, you could cheat a little (but don't use this technique excessively, it leads down a dark road...)
public void DoSomething<T>(List<T> object) where T : ....
{
//do what you want here
}
public void CallIt(Type t, object o) //o is List<Foo>
{
this.GetType().GetMethod("DoSomething").MakeGenericMethod(t).Invoke(o);
}
However I don't see any real benefit to this, as if you don't write any type constraint you gain nothing with using generics instead of objects and IList interface, and if you write any baseclass or interface there, you could just cast your object to that. (For example if you know that T implements IFoo, you could cast o to IList<IFoo> and have every benefit of List<Foo>...

Compile-time and runtime casting c#

I was wondering why some casts in C# are checked at compile-time whereas in other cases the responsibility is dumped on CLR. Like above both are incorrect but handled in a different way.
class Base { }
class Derived : Base { }
class Other { }
static void Main(string[] args)
{
Derived d = (Derived)new Base(); //Runtime InvalidCastException
Derived d = (Derived)new Other(); //Compile-time Cannot convert type...
}
While reading "C# in depth" I've found the information on this topic where autor says:
"If the compiler spots that it’s actually impossible for that cast to work, it’ll trigger a compilation error—and if it’s theoretically allowed but actually incorrect at execution time, the CLR will throw an exception."
Does 'theoretically' mean connected by inheritance hierarchy (some another affinity between objects ?) or it is compiler's internal business?
Upcasts can be checked at compile time - the type system guarantees that the cast succeeds.
Downcasts cannot (in general) be checked at compile time, so they are always checked at runtime.
Unrelated types cannot be cast to each other.
The compiler considers only the static types. The runtime checks the dynamic (runtime) type.
Looking at your examples:
Other x = new Other();
Derived d = (Derived)x;
The static type of x is Other. This is unrelated to Derived so the cast fails at compile time.
Base x = new Base();
Derived d = (Derived)x;
The static type of x is now Base. Something of type Base might have dynamic type Derived, so this is a downcast. In general the compiler can't know from the static type of x if it the runtime type is Base, Derived, of some other subclass of Base. So the decision of whether the cast is allowed is left to the runtime.
If your variable is of Base type, is can be theoretically constructed by Derived constructor, thus being a variable of Derived type actually. At compile time, compiler does not bother itself with trying to figure out whether in each particular case such downcast (representing a variable of Base type as an entity of Derived type) is possible.
Your sample is simple - you create a new class and cast it right away. But what if you get Base from somewhere else, e.g., some method call? Compiler just cannot "guess" what your method is going to return and therefore throw on not throw an error.
When you cast Other, compiler sees that there is no possibility that Other is actually Derived and throws an exception.

Categories