Could someone explain why casting a dynamic object as a class returns that class while using Convert.ChangeType returns a dynamic object, particularly at runtime? For instance:
dynamic dObject = new SomeClass();
var dTest1 = dObject as SomeClass; // returns SomeClass
var dTest2 = Convert.ChangeType(dObject, typeof(SomeClass)); // returns dynamic
The broader problem: I have a series of helper classes which implement a generic interface. I need to pass a list of these classes around to other objects; however the different helper classes use different types for the generic parameter, so I cannot pass a list of the helper classes directly:
interface IHelper<T>
{
IEnumerable<T> Foo();
}
var HelperList = new List<IHelper<T>> // Can't do this because T varies from helper to helper!
So I thought I could fake out the runtime by creating a container class which contains the helper class and the generic type, but leverages dynamics:
class ContainerClass
{
IHelper<dynamic> HelperClass;
Type dType; // Specifies the type for the dynamic object
}
Now I can create and pass a List of ContainerClass around. All the processing works great until I need to assign the results from Foo() back to the destination IEnumerables, at which point I get runtime errors saying that type object cannot be converted to such and such concrete class, even though the unboxed object types match those required. If I attempt similar syntax as in dTest2 above, the runtime is still unable to figure out the "conversion".
I realize this is probably an abuse of dynamic and poor programming practice to boot. I will certainly use a different solution if and when I can identify one, but for now I either need to make this work or go with something less ambitious.
At execution time, there's no such thing as dynamic
really.
However, the call to Convert.ChangeType
is providing a dynamic
value as an argument. Any method call using a dynamic
argument is treated as having a return value of dynamic
, because the compiler doesn't know what the actual signature will be until execution time.
However, if you use a cast, an is
or an as
expression, or a constructor call there's only one type that the result can be - so that's the type of the expression.
As for your broader problem - it's not clear to me that using dynamic
would particularly help you. You may want to declare a base interface for IHelper<T>
- a non-generic interface, that is only ever used for actual IHelper<T>
instances. Then you can have a List<IHelper>
where every element is actually an IHelper<T>
for some T
, but with T
varying across instances. The IHelper
interface isn't really required here, although if your IHelper<T>
interface really contains other members which don't use T
, those could be moved to IHelper
instead. However, just having it for clarity can be useful.
Now, when you need to use a specific IHelper
, then dynamic typing could briefly be useful. You can declare a generic method, and let dynamic typing figure out the type argument at execution time. For example:
private readonly IList<IHelper> helpers;
...
public void UseHelpers()
{
foreach (dynamic helper in helpers)
{
UseHelper(helper); // Figures out type arguments itself
}
}
private void UseHelper<T>(IHelper<T> helper)
{
// Now you're in a generic method, so can use T appropriately
}
See more on this question at Stackoverflow