C# Dynamics: Convert.ChangeType versus Cast

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.

Jon Skeet
people
quotationmark

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
}

people

See more on this question at Stackoverflow