Sûrement si vous avez un IRegistration[]
alors vous êtes downcasting plutôt que upcasting.
Cependant, pour en arriver à votre problème, à quoi ressemble DoStuff()
? A-t-il besoin de connaître l'argument type pour ComponentRegistration<T>
? Sinon, vous pourriez être créer plus d'une classe de base non générique:
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
}
Ensuite, vous pouvez écrire:
foreach (var r in registrations)
{
ComponentRegistration cr = r as ComponentRegistration;
if (cr != null)
{
DoStuff(cr);
}
}
Si vous avez vraiment besoin DoStuff
d'utiliser les informations génériques, vous devrez Utilisez la réflexion pour obtenir le type approprié et l'invoquer. Évitez si possible :)
EDIT: Bon, voici un exemple de la méchanceté de la réflexion. Il n'essaie pas de rendre compte des interfaces génériques, car cela devient encore plus poilu.
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: Notez que si vous êtes dans une situation où tous les les membres sont issus de la classe concernée, et si vous utilisez C# 4, vous pouvez utiliser la liaison dynamique:
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));
}
}
Malheureusement, je ne connais aucun moyen de vérifier si elle va réussir à se lier à la méthode avec succès sans juste essayer et attraper l'exception pertinente (ce qui serait sombre).Peut-être que Eric sera en mesure de nous dire :)
Quelle est la signature de DoStuff? –
Ah, Eric est là. Je n'ai pas besoin de revenir à cette question - il est garanti d'obtenir une excellente réponse :) –
DoStuff attache un intercepteur de château. Malheureusement, je ne sais comment faire cela dans leur interface fluide avec les implémentations ComponentRegistration ou BasedOnDescriptor de IRegistration. Cependant, je sais que tous les éléments d'enregistrement sont l'un de ces deux éléments. –