C # appel méthode générique dynamique [double]
-
26-09-2019 - |
Question
Cette question a déjà une réponse ici:
Étant donné les interfaces suivantes:
interface IEntity
{
int Id{get;}
}
interface IPerson : IEntity
{
string Name{get;}
int Age{get;}
}
interface ITeacher : IPerson
{
string StaffId{get;}
}
interface IStudent : IPerson
{
string StudentId{get;}
string Courses{get;}
}
interface IRepository
{
T Get<T>(int id) where T : IEntity
}
Je les classes suivantes dans mon espace de noms
public class EntityBase() : IEntity
{
int Id{get;set;}
}
public class Teacher : EntityBase, ITeacher{}
public class Sudent : EntityBase, IStudent{}
Je suis actuellement ce IRepository comme la mise en œuvre suivante:
class Repository: IRepository
{
IDataContext Context{get;set;}
T Get<T>(int id) where T : EntityBase
{
if(typeof(T) == typeof(Teacher))
return Context.Get<ITeacher>(id);
if(typeof(T) == typeof(Sudent))
return Context.Get<ISudent>(id);
throw new Exception("Unknown Interface " + typeof(T).Name);
}
}
Y at-il un Betterway de mettre en œuvre ce? Étant donné que notre contexte n'a pas connaissance de nos types de données (enseignants, étudiants), seulement ses interfaces (ITeacher, IStudent).
quelque chose peut comme ce travail?
class Repository: IRepository
{
T Get<T>(int id) where T : EntityBase
{
var MyInterface = FindInterface<T>();
return Context.Get<MyInterface>(id);
}
}
La solution
Je pense que cela va faire:
class Repository: IRepository
{
IDataContext Context{get;set;}
T Get<T>(int id) where T : EntityBase
{
string[] interfaceList = new string[]
{ "ITeacher", "IStudent"};
Type interfaceType = null;
foreach (string s in interfaceList)
{
var types = typeof(T).FindInterfaces((x, y) => x.Name == y.ToString(), s);
if (types.Length > 0)
interfaceType = types[0];
}
if (interfaceType == null)
throw new Exception("Unknown Interface " + typeof(T).Name);
MethodInfo method = typeof(Context).GetMethod("Get");
MethodInfo generic = method.MakeGenericMethod(interfaceType);
var returnValue = generic.Invoke(Context, new object[] { id });
return (T)Convert.ChangeType(returnValue, typeof(T));
}
}
EDIT: Comme je ne sais pas le nom de votre espace de noms, j'ai utilisé la propriété Nom pour filtrer les interfaces. En usage réel du monde, je suggère que vous utilisez FullName juste pour être sûr, comme ceci:
...
string[] interfaceList = new string[]
{ "MyNamespace.ITeacher", "MyNamespace.IStudent"};
...
var types = typeof(T).FindInterfaces((x, y) => x.FullName == y.ToString(), s);
Autres conseils
Je pense que vous pouvez accomplir cela à travers la réflexion en trouvant la méthode Get la classe de contexte, et en invoquant comme un appel générique pour le type fourni par l'appelant T. Je n'ai pas testé, mais le code devrait ressembler à ceci :
T Get<T>(int id) where T : EntityBase
{
Type context = Context.GetType();
MethodInfo getMethod = context.GetMethod("Get", BindingFlags.Public);
MethodInfo genericGet = getMethod.MakeGenericMethod(new [] {typeof(T)});
return (T)genericGet.Invoke(Context, new object[] { id } );
}
Il me semble que vous l'entendez l'inverse. Vous ne voulez pas passer les types d'interface à Context.Get<>
, avez-vous?
// is this what you mean?
if (typeof(T) == typeof(ITeacher))
return Context.Get<Teacher>(id);