C# 4.0 寻找一个合适的方法来实现我的通用工厂
我正在努力实现一个工厂对象。以下是上下文: 我在一个定制商店的项目中。为了读取/写入记录,我在POCO模型/分离存储库中编写了以下代码:C# 4.0 寻找一个合适的方法来实现我的通用工厂,c#-4.0,factory-pattern,C# 4.0,Factory Pattern,我正在努力实现一个工厂对象。以下是上下文: 我在一个定制商店的项目中。为了读取/写入记录,我在POCO模型/分离存储库中编写了以下代码: public class Id { /* skip for clarity*/} // My custom ID representation public interface IId { Id Id { get; set; } } public interface IGenericRepository<T> where T : IId
public class Id { /* skip for clarity*/} // My custom ID representation
public interface IId
{
Id Id { get; set; }
}
public interface IGenericRepository<T> where T : IId
{
T Get(Id objectID);
void Save(T @object);
}
public interface IContext
{
TRepository GetRepository<T, TRepository>()
where TRepository : IGenericRepository<T>
where T:IId;
IGenericRepository<T> GetRepository<T>()
where T:IId;
}
public class Id{/*为清楚起见跳过*/}//我的自定义Id表示
公共接口IId
{
Id{get;set;}
}
公共接口IGenericRepository,其中T:IId
{
T Get(Id objectID);
无效保存(T@object);
}
公共接口IContext
{
TRepository GetRepository()
存储位置:IGenericRepository
式中T:IId;
IGenericRepository GetRepository()
式中T:IId;
}
我的IContext接口定义了两种存储库。
前者适用于只有get/save方法的标准对象,后者允许我为特定类型的对象定义特定的方法。例如:
public interface IWebServiceLogRepository : IGenericRepository<WebServiceLog>
{
ICollection<WebServiceLog> GetOpenLogs(Id objectID);
}
公共接口IWebServiceLogRepository:IGenericRepository
{
ICollection GetOpenLogs(Id objectID);
}
这是消费代码,我可以做其中一个:
MyContext.GetRepository().Get(myID)代码>-->标准获取
MyContext.GetRepository().GetOpenLogs(myID)代码>-->特定操作
public class BaseRepository<T> : IGenericRepository<T>
where T : IId, new()
{
public virtual T Get(Id objectID){ /* provider specific */ }
public void Save(T @object) { /* provider specific */ }
}
internal class WebServiceLogRepository: BaseRepository<WebServiceLog>, IWebServiceLogRepository
{
public ICollection<WebServiceLog> GetByOpenLogsByRecordID(Id objectID)
{
/* provider specific */
}
}
公共类基存储库:IGenericRepository
其中T:IId,new()
{
公共虚拟T Get(Id objectID){/*特定于提供程序的*/}
public void Save(T@object){/*特定于提供程序的*/}
}
对于自定义存储库,我只是继承了基本存储库:
public class BaseRepository<T> : IGenericRepository<T>
where T : IId, new()
{
public virtual T Get(Id objectID){ /* provider specific */ }
public void Save(T @object) { /* provider specific */ }
}
internal class WebServiceLogRepository: BaseRepository<WebServiceLog>, IWebServiceLogRepository
{
public ICollection<WebServiceLog> GetByOpenLogsByRecordID(Id objectID)
{
/* provider specific */
}
}
内部类WebServiceLogRepository:BaseRepository、IWebServiceLogRepository
{
公共ICollection GetByOpenLogsByRecordID(Id objectID)
{
/*特定于提供商*/
}
}
上面的一切都还可以(至少我认为还可以)。我现在正在努力实现MyContext类。我在我的项目中使用MEF用于其他目的。但由于MEF还不支持通用的导出,我没有找到实现目标的方法
我的上下文类现在看起来像:
[Export(typeof(IContext))]
public class UpdateContext : IContext
{
private System.Collections.Generic.Dictionary<Type, object> m_Implementations;
public UpdateContext()
{
m_Implementations = new System.Collections.Generic.Dictionary<Type, object>();
}
public TRepository GetRepository<T, TRepository>()
where T : IId
where TRepository : IGenericRepository<T>
{
var tType = typeof(T);
if (!m_Implementations.ContainsKey(tType))
{
/* this code is neither working nor elegant for me */
var resultType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(
(a) => a.GetTypes()
).Where((t)=>t.GetInterfaces().Contains(typeof(TRepository))).Single();
var result = (TRepository)resultType.InvokeMember("new", System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { this });
m_Implementations.Add(tType, result);
}
return (TRepository)m_Implementations[tType];
}
public IGenericRepository<T> GetRepository<T>() where T : IId
{
return GetRepository<T, IGenericRepository<T>>();
}
}
[导出(typeof(IContext))]
公共类UpdateContext:IContext
{
private System.Collections.Generic.Dictionary m_实现;
公共UpdateContext()
{
m_Implementations=new System.Collections.Generic.Dictionary();
}
公共存储库GetRepository()
T:IId在哪里
存储位置:IGenericRepository
{
var tType=类型(T);
if(!m_Implementations.ContainsKey(tType))
{
/*这个代码对我来说既不起作用也不优雅*/
var resultType=AppDomain.CurrentDomain.GetAssemblys()。SelectMany(
(a) =>a.GetTypes()
)其中((t)=>t.GetInterfaces()包含(typeof(TRepository))).Single();
var result=(TRepository)resultType.InvokeMember(“新建”,System.Reflection.BindingFlags.CreateInstance,null,null,新对象[]{this});
m_Implementations.Add(tType,result);
}
返回(TRepository)m_实现[tType];
}
公共IGenericRepository GetRepository(),其中T:IId
{
返回GetRepository();
}
}
我希望能得到一些帮助,用这个非常常见的场景来解惑我的头脑我不确定我是否正确地理解了你,但我认为你可能把事情复杂化了。首先,确保您设计的代码独立于任何工厂、依赖项注入框架或组合框架 首先,让我们看看您希望您的调用代码是什么样子的,这就是您所说的:
MyContext.GetRepository<Customer>().Get(myID); --> standard get
MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID);
MyContext.GetRepository().Get(myID);-->标准件
MyContext.GetRepository().GetOpenLogs(myID);
你不必同意我下面的命名选择,但它表明了我对你的代码的理解,如果我错了,你可以告诉我。现在,我觉得打电话会更简单,就像这样:
RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}
public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
RepositoryFactory.New().Get(myId);
RepositoryFactory.New().GetOpenLogs(myId);
第1行:
因为这里的类型是IRepository,所以很清楚返回类型是什么,对于基础IRepository,T类型是什么
第2行:
工厂返回的类型是IWebServiceLogRepository。在这里,您不需要指定实体类型,您的接口在逻辑上已经实现了IRepository。无需再次指定此项
因此,这些的界面如下所示:
RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}
public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
公共接口IRepository
{
T Get(对象Id);
T保存(T对象);
}
公共接口IWebServiceLogRepository:IRepository
{
列出GetOpenLogs(对象Id);
}
现在我认为实现和工厂代码会更简单,因为工厂只需要知道一种类型。第1行的类型是IRepository,第2行的类型是IWebServiceLogRepository
试着这样做,然后试着重写代码,简单地找到实现这些类型的类并实例化它们
最后,就MEF而言,您可以继续使用它,但Castle Windsor确实会让您的工作更简单,因为它让您可以专注于您的体系结构和代码设计,而且使用起来非常简单。您只在应用程序启动代码中引用Castle。剩下的代码只是使用依赖注入模式设计的,该模式与框架无关
如果其中一些不清楚,请告诉我您是否希望我也用您的存储库的实现代码更新此答案
更新
下面是解析实现的代码。您没有使用Activator类,这让您自己变得更难了
如果您使用Activator,并且像我在下面的方法中所做的那样只使用一个泛型参数,那么应该可以。请注意,代码有点粗糙,但您可以理解:
public static T GetThing<T>()
{
List<Type> assemblyTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()).ToList();
Type interfaceType = typeof(T);
if(interfaceType.IsGenericType)
{
var gens = interfaceType.GetGenericArguments();
List<Type> narrowed = assemblyTypes.Where(p => p.IsGenericType && !p.IsInterface).ToList();
var implementations = new List<Type>();
narrowed.ForEach(t=>
{
try
{
var imp = t.MakeGenericType(gens);
if(interfaceType.IsAssignableFrom(imp))
{
implementations.Add(imp);
}
}catch
{
}
});
return (T)Activator.CreateInstance(implementations.First());
}
else
{
List<Type> implementations = assemblyTypes.Where(p => interfaceType.IsAssignableFrom(p) && !p.IsInterface).ToList();
return (T)Activator.CreateInstance(implementations.First());
}
}
publicstatict GetThing()
{
列表