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 :)