我正在努力实现工厂对象。这是上下文:
我在一个项目中有一个自定义商店。为了读/写记录,我将这段代码写在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
{
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;
}
我的IContext接口定义了两种存储库。 前者用于仅带有get / save方法的标准对象,后者允许我为特定类型的对象定义特定方法。例如:
public interface IWebServiceLogRepository : IGenericRepository<WebServiceLog>
{
ICollection<WebServiceLog> GetOpenLogs(Id objectID);
}
消费代码我可以做到这一点:
MyContext.GetRepository<Customer>().Get(myID);
- &gt;标准获取MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID);
- &gt;具体操作由于大多数对象存储库仅限于获取和保存操作,因此我编写了一个通用存储库:
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 */
}
}
以上所有内容都可以(至少我认为没关系)。我现在正在努力实现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>>();
}
}
我很感激帮助我解决这个相当常见的情况
答案 0 :(得分:1)
不确定我是否理解正确,但我认为你可能过于复杂化了。首先,确保您设计的代码独立于任何工厂或依赖注入框架或组合框架。
对于初学者,让我们看看你希望你的调用代码看起来像什么,这就是你所说的:
MyContext.GetRepository<Customer>().Get(myID); --> standard get
MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID);
您不必同意下面的命名选项,但它表明了我的代码,我可以告诉我,如果我错了。现在,我觉得这样的调用会更简单:
RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
第1行: 因为这里的类型是IRepository,所以很清楚返回类型是什么,以及T类型对于基础IRepository是什么。
第2行: 这里的返回类型是IWebServiceLogRepository。在这里,您不需要指定实体类型,您的界面在逻辑上已经实现了IRepository。没有必要再次指定。
所以你的界面看起来像这样:
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}
public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
现在我认为这样的实现和工厂代码会更简单,因为工厂只需知道一种类型。在第1行,类型是IRepository,在第2行,IWebServiceLogRepository。
尝试一下,尝试重写代码,只需找到实现这些类型的类并实例化它们。
最后,就MEF而言,你可以继续使用它,但Castle Windsor会让你的事情变得更加简单,因为它让你专注于你的架构和代码设计,而且它非常简单易用。您只在应用启动代码中引用Castle。您的其余代码只是使用依赖注入模式设计,这与框架无关。
如果其中一些不清楚,请告诉我您是否希望我使用您的存储库的实施代码更新此答案。
这是解决实现的代码。你不使用Activator类让自己变得有点困难。
如果你使用Activator并且只使用一个Generic参数,就像我在下面的方法中所做的那样,你应该没问题。注意代码有点粗糙,但你明白了:
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());
}
}