我们正在尝试使用Linq2SQl实现存储库模式,并且数据上下文被懒惰地初始化。
Repository类实现了IRepository
public class Repository<T> : IRepository<T> where T : class
{
private readonly Table<T> _table;
public Repository(IDataContextAdapter dataContextAdapter)
{
_table = dataContextAdapter.Context.GetTable<T>();
}
...
}
Data Access使用委托给存储库
public class UserDataAccess : IUserDataAccess
{
private readonly IRepository<User> _userRepository;
public UserDataAccess(IDataContextAdapter dataContextAdapter,
Func<IDataContextAdapter, IRepository<User>> userRepository)
{
_userRepository = userRepository(dataContextAdapter);
}
}
我想知道如何在统一容器中统一定义存储库。
目前我有以下内容,但我不想为User,Employer等每个具体的存储库类重复它。
UnityContainer.RegisterType<Func<IDataContextAdapter, IRepository<User>>>(
new InjectionFactory(c =>
new Func<IDataContextAdapter, IRepository<User>>(
context => new Repository<User>(context))
)
);
我正在寻找一种通常定义类型的方法,比如
UnityContainer.RegisterType<Func<IDataContextAdapter, IRepository<T>>>(
new InjectionFactory(c =>
new Func<IDataContextAdapter, IRepository<T>>(
context => new Repository<T>(context))
)
);
我尝试在'&lt;&gt;'上应用typeof操作,但没有取得多大成功。
答案 0 :(得分:0)
我无法理解你想要达到的目标,但我提出了一个建议,即我脑子里关闭的半逻辑事物是什么。
首先放弃你的代表。 (或解释它的用途)。以这种方式定义UserDataAccess:
public class UserDataAccess : IUserDataAccess
{
private readonly IRepository<User> _userRepository;
public UserDataAccess(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
}
现在您的注册将如下所示:
DataContextAdapter context = new DataContextAdapter();
UnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType(typeof (IRepository<>), typeof (Repository<>));
unityContainer.RegisterType<IUserDataAccess, UserDataAccess>();
unityContainer.RegisterInstance<IDataContextAdapter>(context);
然后你这样解决:
IUserDataAccess test = unityContainer.Resolve<IUserDataAccess>();
将创建UserDataAccess并且右侧关闭类型Repoistory&lt;&gt;将被注入构造函数中。反过来,DataContextAdapter将被注入Repoistory&lt;&gt;的构造函数中。
更新1
根据原始问题中的信息,链接到您上面提供的信息,是否有理由说明以下内容对您不起作用?
unityContainer.RegisterType(typeof (IRepository<>), typeof (Repository<>));
unityContainer.RegisterType<IUserDataAccess, UserDataAccess>();
DataContextAdapter context1 = new DataContextAdapter();
DataContextAdapter context2 = new DataContextAdapter();
IUnityContainer container1 = unityContainer.CreateChildContainer();
IUnityContainer container2 = unityContainer.CreateChildContainer();
container1.RegisterInstance<IDataContextAdapter>(context1);
container2.RegisterInstance<IDataContextAdapter>(context2);
IUserDataAccess test1 = container1.Resolve<IUserDataAccess>();
IUserDataAccess test2 = container2.Resolve<IUserDataAccess>();
我仍然认为没有理由让代表和注射工厂变得复杂。您需要在不同的代码路径中使用不同的数据上下文,因此只需在容器中注入不同的实例,如下所示。当您不再需要容器时,可以将其丢弃。
您的要求中是否有其他任何内容未能通过此解决方案实现?
更新2
在回应上述评论时,我想澄清一点,您不必使用上述方法预先注册或实例化上下文。您可以在使用它们的站点上进行操作:
// When you need context, obtain it
DataContextAdapter context1 = new DataContextAdapter();
//Register it for the local scope
IUnityContainer container1 = unityContainer.CreateChildContainer();
container1.RegisterInstance<IDataContextAdapter>(context1);
// Resolve the dependency
IUserDataAccess test1 = container1.Resolve<IUserDataAccess>();
// Use your interface
......
// Release and dispose your context
container1.Dispose
要点的重点是你控制实例化它们的地点和时间
答案 1 :(得分:0)
.NET不允许部分关闭的类型。 http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/01/partially-closed-generic-types.aspx这就是为什么你不能以通用的方式做你想要实现的目标。在运行时,您可以使用像Func&lt;,&gt;这样的开放类型。或关闭类型,如Func<IDataContextAdapter, IRepository<User>>
简化,Unity维护类型映射的字典,其中type是非泛型类型或通用开放类型或通用封闭类型。因此,不可能映射不属于这些类别的类型。
如果我们能够在运行时提出一种快速的方法来匹配Func<IDataContextAdapter, IRepository<T>>
,那么就可以为Unity编写一个扩展来执行解析。但是,似乎没有可能在不使用反射的情况下进行此类匹配,并且您通常会尝试在出于性能原因每次解析类型时避免使用反射。在最坏的情况下,您在第一个分辨率期间使用反射只能在运行中生成IL,这样可以在不进行反射的情况下创建对象。不幸的是,在我们的案例中,这是不可能的。
我在Unity级别上解决此问题的唯一方法就是每次请求Func<IDataContextAdapter, IRepository<Something>>
时,都要检查是否已经注册,如果没有注册,请在动态工厂生成。
换句话说,没有简单的方法可以做到这一点。
我建议的另一种方法是在引导程序样式中执行多次注册,但您已经知道此选项。
您还可以定义这样的通用工厂:
public class GenericDataServiceFactory<TResult, TModel>
{
private UnityContainer container;
private Func<IDataContextAdapter, IRepository<TModel>> _repositoryFactory;
public GenericDataServiceFactory(Func<IDataContextAdapter, IRepository<TModel>> repositoryFactory)
{
_repositoryFactory = repositoryFactory;
}
public TResult CreateUserDataAccess(IDataContextAdapter dataContextAdapter)
{
Type targerType = typeof (TResult);
// Via reflection find constructor like this
// TResult(IDataContextAdapter dataContextAdapter, Func<IDataContextAdapter,IRepository<Something>> repositoryFactory)
// Invoke it with dataContextAdapter and _repositoryFactory and return the result
return newObject;
}
}
但话说回来,你每次都会经历反思,我相信你不想这样做。