J'essaie d'utiliser Generics with Reflection dans C# pour construire une méthode capable de gérer plusieurs classes. J'utilise une DLL tierce qui a un tas de classes et sur ces classes, il y a une méthode que j'appelle. Ils renvoient tous des types de retour différents, mais je fais le même traitement une fois que je récupère l'objet (dans mon exemple ci-dessous, ce serait AreaA et AreaB). Fondamentalement, je veux développer une méthode qui prend le nom de classe et le type de retour attendu en tant que variables génériques, puis appelle la méthode correcte (methodName) qui est fourni en tant que paramètre de cette méthode.Réflexion utilisant des génériques et liaison tardive. Comment lancer à l'exécution?
Le programme ci-dessous compile bien et s'exécute sans erreur, mais le problème est le type attendu de la variable 'area'. Dans les instructions ci-dessous, la première ligne est castée en (TArea), et si je survole dessus Dans Visual Studio, l'intellisense montre la propriété 'nom', mais en tapant area.name ne me donne pas la valeur. Je dois taper (zone (AreaA)) .name.
Le problème est le type 'AreaA' pourrait être un autre type au moment de l'exécution. Dans cet exemple, 'AreaB' pour que je puisse coder en dur une distribution.
Comment puis-je accomplir la coulée de la variable « zone » au type approprié me permettant de voir les méthodes/propriétés publiques de la classe de 3e parties? REMARQUE: Dans mon exemple, tout est dans la même classe, mais en réalité les définitions de ServiceA, ServiceB, AreaA et AreaB seront dans une DLL tierce.
Comme toujours, merci à l'avance!
Figure 1 - propriété 'zone' variable ne peut obtenir 'nom' si casté en 'AreaA'
area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
AreaA areaa = (AreaA)dfpMethod.Invoke(instance, new object[] { "Area123" });
Figure 2. - Programme complet
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
namespace ReflectionExample
{
class Sample
{
class ServiceA
{
public int size {get; set;}
public string name {get; set;}
public ServiceA()
{
name = "TestA";
size = 100;
}
public AreaA doWork(string name)
{
return new AreaA(name);
}
}
class AreaA
{
public string name { get; set;}
public AreaA(string name)
{
this.name = name;
}
public AreaA()
{
}
}
class ServiceB
{
public int size { get; set; }
public string name { get; set; }
public ServiceB()
{
name = "TestB";
size = 50;
}
public AreaB doWork(string name)
{
return new AreaB(name);
}
}
class AreaB
{
public string name { get; set; }
public AreaB(string name)
{
this.name = name;
}
public AreaB()
{
}
}
static void Main(string[] args)
{
runService<ServiceA, AreaA>("doWork");
}
private static void runService<TService, TArea>(string methodName)
where TService : class, new()
where TArea : class, new()
{
//Compile time processing
Type areaType = typeof(TArea);
Type serviceType = typeof(TService);
//Print the full assembly name and qualified assembly name
Console.WriteLine("AreaType--Full assembly name:\t {0}.", areaType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("AreaType--Qualified assembly name:\t {0}.", areaType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
Console.WriteLine("ServiceType--Full assembly name:\t {0}.", serviceType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("ServiceType--Qualified assembly name:\t {0}.", serviceType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
//This is done because in my code, the assembly doesn't reside in the executiy assembly, it is only setup as a reference
var assembly = Assembly.Load(serviceType.Assembly.FullName);
//Initialize the generic area
TArea area = default(TArea);
//Get an instance of the service so I can invoke the method later on
var instance = Activator.CreateInstance(serviceType);
//Get the methodInfo for the methodName supplied to the runService method
MethodInfo dfpMethod = serviceType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
//area is type casted to (TArea), the intellisense shows the property 'name', but typing area.name doesn't give me the value
//I have to type ((AreaA)area).name. Problem is the type 'AreaA' could be another type. In this example, 'AreaB'
area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
AreaA areaa = (AreaA)dfpMethod.Invoke(instance, new object[] { "Area123" });
Console.WriteLine();
}
}
}
en tant que nœud de côté: si vous attendez plusieurs appels à 'runService', je pense que vous devriez en faire une classe afin que vous ne avoir à faire une fois le chargement de l'assembly et la création de l'instance de service. En outre, vous pouvez mettre en cache les informations de méthode pour une méthode dans un dictionnaire par nom de méthode (ou mieux encore créer un délégué à partir des informations de méthode). – Alex