给出以下接口:
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
}
我的命名空间中有以下类
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<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);
}
}
有更好的实施方法吗?鉴于我们的Context不知道我们的数据类型(教师,学生),只知道它的接口(ITeacher,IStudent)。
这样的事情可以吗?
class Repository: IRepository
{
T Get<T>(int id) where T : EntityBase
{
var MyInterface = FindInterface<T>();
return Context.Get<MyInterface>(id);
}
}
答案 0 :(得分:9)
我认为这样做:
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));
}
}
编辑:由于我不知道您的命名空间的名称,我使用了Name属性来过滤接口。在实际使用中,我建议您使用FullName以确保,如下所示:
...
string[] interfaceList = new string[]
{ "MyNamespace.ITeacher", "MyNamespace.IStudent"};
...
var types = typeof(T).FindInterfaces((x, y) => x.FullName == y.ToString(), s);
答案 1 :(得分:5)
我认为你可以通过在Context类中找到Get方法并将其作为调用者提供的类型T的泛型调用来调用它来实现这一点。我没有测试过这个,但代码应该看起来像这样:
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 } );
}
答案 2 :(得分:0)
在我看来,你的意思是反过来。您不希望将接口类型传递给Context.Get<>
,是吗?
// is this what you mean?
if (typeof(T) == typeof(ITeacher))
return Context.Get<Teacher>(id);
如果是,则需要使用MakeGenericMethod
,请参阅this以获取示例(请注意缓存部分)。
如果不是,您可能会误解LINQ和/或Repository模式的一些概念。
但是我很好奇为什么你决定使用接口。无论如何LINQ对象都是POCO,为什么要添加另一层抽象,它涉及(grrsh!)通过反射调用DataContext上的泛型方法?
答案 3 :(得分:0)
简单的return Context.Get<T>(id)
可以完成如下:
class Repository : IRepository
{
public IDataContext Context { get; set; }
public T Get<T>(int id) where T : IEntity, new()
{
return Context.Get<T>(id);
}
}
以下是您的对象/接口模型,其中包含Context
的实现 interface IEntity
{
int Id{get;}
}
interface IPerson : IEntity
{
}
interface ITeacher : IPerson
{
}
interface IStudent : IPerson
{
}
interface IDataContext
{
T Get<T>(int id) where T:new();
}
interface IRepository
{
T Get<T>(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<T>: 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<T>(int i) where T:new()
{
if (i<store.Count)
{
return (T)store[i];
}
else
{
return default(T);
}
}
}
现在终于主要的方法类来证明它们很好地挂在一起。
using System;
using System.Collections;
class MyClass
{
static void Main(string[] args)
{
Context<Teacher> teachersContext = new Context<Teacher>(100);//contructs a db of 100 teachers
Context<Student> studentsContext = new Context<Student>(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<Teacher>(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<Student>(35); //get student number 35
Console.WriteLine("Student Id: {0} ", student1.Id);
Console.ReadLine();
}