How to up-cast to a generic object?

Question!

I have an array of Castle windsor registration components of type IRegistration[]

In this case ComponentRegistration<T> : IRegistration

For each element in my array, if it can be upcast to ComponentRegistration<> I would like to upcast it back to ComponentRegistration<T> and process it. How exactly would I do this?

I got as far as

foreach (var r in registrations) {
  if(typeof(ComponentRegistration<>).IsAssignableFrom(r.GetType())) {
    var cr = CAST r SOMEHOW
    DoStuff(cr);
  }


Answers

If the class you're trying to upcast to is a non-generic derived from the generic, you can get around this problem by casting through Object:

abstract class A<T> where T : A<T>
{
    T derived;
    void foo()
    {
        B b1 = (B)derived;      // Error CS0030: 'Cannot convert type 'T' to 'B'
        B b2 = (B)(Object)derived;  // Ok
    }
};

class B : A<B> { };


Surely if you've got an IRegistration[] then you're downcasting rather than upcasting.

However, to get to your problem, what does DoStuff() look like? Does it need to know the type argument for ComponentRegistration<T>? If not, you might be best creating a non-generic base class:

public abstract class ComponentRegistration : IRegistration
{
    // Anything in the original API which didn't use T
}

public class ComponentRegistration<T> : ComponentRegistration
{
    // The bits which need T
}

Then you could write:

foreach (var r in registrations)
{
    ComponentRegistration cr = r as ComponentRegistration;
    if (cr != null)
    {
        DoStuff(cr);
    }
}

If you really need DoStuff to use the generic information, you'll have to use reflection to get the appropriate type and invoke it. Avoid if possible :)

EDIT: Okay, here's an example of the reflection nastiness. It doesn't try to account for generic interfaces, as that gets even hairier.

using System;
using System.Reflection;

class Test
{   
    static void Main()
    {
        Delegate[] delegates = new Delegate[]
        {
            (Action<int>) (x => Console.WriteLine("int={0}", x)),
            (Action<string>) (x => Console.WriteLine("string={0}", x)),
            (Func<int, int>) (x => x + 1)
        };

        MethodInfo genericPerformAction = typeof(Test).GetMethod
                                                       ("PerformAction");

        foreach (Delegate del in delegates)
        {
            Type t = DiscoverTypeArgument(del, typeof(Action<>));
            if (t == null)
            {
                // Wrong type (e.g. the Func in the array)
                continue;
            }
            MethodInfo concreteMethod = genericPerformAction.MakeGenericMethod
                (new[] { t } );
            concreteMethod.Invoke(null, new object[] { del });
        }
    }

    public static void PerformAction<T>(Action<T> action)
    {
        Console.WriteLine("Performing action with type {0}", typeof(T).Name);
        action(default(T));
    }

    /// <summary>
    /// Discovers the type argument for an object based on a generic
    /// class which may be somewhere in its class hierarchy. The generic
    /// type must have exactly one type parameter.
    /// </summary>
    /// <returns>
    /// The type argument, or null if the object wasn't in
    /// the right hierarchy.
    /// </returns>
    static Type DiscoverTypeArgument(object o, Type genericType)
    {
        if (o == null || genericType == null)
        {
            throw new ArgumentNullException();
        }
        if (genericType.IsInterface ||
            !genericType.IsGenericTypeDefinition || 
            genericType.GetGenericArguments().Length != 1)
        {
            throw new ArgumentException("Bad type");
        }

        Type objectType = o.GetType();
        while (objectType != null)
        {
            if (objectType.IsGenericType &&
                objectType.GetGenericTypeDefinition() == genericType)
            {
                return objectType.GetGenericArguments()[0];
            }
            objectType = objectType.BaseType;
        }
        return null;
    }
}

EDIT: Note that if you're in a situation where all the members are derived from the relevant class, and if you're using C# 4, you can use dynamic binding:

using System;
using System.Reflection;

class Test
{   
    static void Main()
    {
        Delegate[] delegates = new Delegate[]
        {
            (Action<int>) (x => Console.WriteLine("int={0}", x)),
            (Action<string>) (x => Console.WriteLine("string={0}", x)),
            (Action<long>) (x => Console.WriteLine("long={0}", x)),
        };

        foreach (dynamic del in delegates)
        {
            // Yay for dynamic binding
            PerformAction(del);
        }
    }

    public static void PerformAction<T>(Action<T> action)
    {
        Console.WriteLine("Performing action with type {0}", typeof(T).Name);
        action(default(T));
    }
}

Unfortunately I don't know of any way of testing whether it's going to manage to bind to the method successfully without just trying it and catching the relevant exception (which would be grim). Maybe Eric will be able to tell us :)

By : Jon Skeet


Unfortunately you cannot do this without either

  1. Having a non-generic form of ComponentRegistration
  2. Knowing T
  3. Using a reflection hack

EDIT the reflection hack

Essentially you'll need to use reflection to grab the runtime type. Inspect the type to grab the generic T in ComponentRegistration. Then use that T to instantiate an instance of method DoStuff and pass in the object as a parameter.

By : JaredPar


This video can help you solving your question :)
By: admin