C#调用动态通用方法

给出以下接口:

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(int id) where T : IEntity } 

我的命名空间中有以下类

 public class EntityBase() : IEntity { int Id{get;set;} } public class Teacher : EntityBase, ITeacher{} public class Sudent : EntityBase, IStudent{} 

目前我正在实现这个IRepository如下:

 class Repository: IRepository { IDataContext Context{get;set;} T Get(int id) where T : EntityBase { if(typeof(T) == typeof(Teacher)) return Context.Get(id); if(typeof(T) == typeof(Sudent)) return Context.Get(id); throw new Exception("Unknown Interface " + typeof(T).Name); } } 

是否有更好的实施方法? 鉴于我们的Context不了解我们的数据类型(教师,学生),只知道它的接口(ITeacher,IStudent)。

可以这样的工作吗?

 class Repository: IRepository { T Get(int id) where T : EntityBase { var MyInterface = FindInterface(); return Context.Get(id); } } 

我想这会做:

 class Repository: IRepository { IDataContext Context{get;set;} T Get(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)); } } 

编辑:由于我不知道您的命名空间的名称,我使用了Name属性来过滤接口。 在实际使用中,我建议您使用FullName以确保,如下所示:

 ... string[] interfaceList = new string[] { "MyNamespace.ITeacher", "MyNamespace.IStudent"}; ... var types = typeof(T).FindInterfaces((x, y) => x.FullName == y.ToString(), s); 

我认为你可以通过在Context类中找到Get方法并将其作为调用者提供的类型T的generics调用来调用它来实现这一点。我没有测试过这个,但代码看起来应该是这样的:

 T Get(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 } ); } 

它看起来像你的意思是相反的方式。 您不希望将接口类型传递给Context.Get<> ,是吗?

 // is this what you mean? if (typeof(T) == typeof(ITeacher)) return Context.Get(id); 

如果是,则需要使用MakeGenericMethod ,请参阅此示例(请注意缓存部分)。
如果不是,您可能会误解LINQ和/或Repository模式的一些概念。

但是我很好奇为什么你决定使用接口。 LINQ对象无论如何都是POCO,为什么要添加另一层抽象,涉及(grrsh!)通过reflection调用DataContext上的generics方法?

一个简单的return Context.Get(id)可以完成如下:

 class Repository : IRepository { public IDataContext Context { get; set; } public T Get(int id) where T : IEntity, new() { return Context.Get(id); } } 

以下是您的对象/接口模型,其中包含Context的实现

  interface IEntity { int Id{get;} } interface IPerson : IEntity { } interface ITeacher : IPerson { } interface IStudent : IPerson { } interface IDataContext { T Get(int id) where T:new(); } interface IRepository { T Get(int id) where T : IEntity , new() ; } public class EntityBase : IEntity { public virtual int Id{get;set;} } public class Teacher : EntityBase, ITeacher { int id=0; public override int Id { get { return this.id; } set { this.id = value; } } } public class Student : EntityBase, IStudent { int id=0; public override int Id { get { return this.id; } set { this.id = value; } } } class Context: IDataContext where T: EntityBase, new() { ArrayList store; public Context(int dataSize) { store = new ArrayList(dataSize); for (int i = 0; i < dataSize; i++) { T t = new T(); t.Id = i; store.Add(t); } } public T Get(int i) where T:new() { if (i 

现在最后主要的方法类来certificate它们很好地挂在一起。

  using System; using System.Collections; class MyClass { static void Main(string[] args) { Context teachersContext = new Context(100);//contructs a db of 100 teachers Context studentsContext = new Context(100);//contructs a db of 100 teachers Repository repo = new Repository(); // set the repository context and get a teacher repo.Context = teachersContext; Teacher teacher1 = repo.Get(83); //get teacher number 83 Console.WriteLine("Teacher Id:{0} ", teacher1.Id); // redirect the repositry context and now get a student repo.Context = studentsContext; Student student1 = repo.Get(35); //get student number 35 Console.WriteLine("Student Id: {0} ", student1.Id); Console.ReadLine(); }