C# 具有工作单元模式的泛型问题
我需要一些关于工作单元+存储库+IoC模式设计的帮助。我有几个定义如下的接口:C# 具有工作单元模式的泛型问题,c#,design-patterns,inversion-of-control,repository-pattern,unit-of-work,C#,Design Patterns,Inversion Of Control,Repository Pattern,Unit Of Work,我需要一些关于工作单元+存储库+IoC模式设计的帮助。我有几个定义如下的接口: public interface IRepository<T> { T GetEntity(int id); } public interface IUserRepository : IRepository<User> { User GetUserByXyz(int id); } public interface IUnitOfWork { T
public interface IRepository<T>
{
T GetEntity(int id);
}
public interface IUserRepository : IRepository<User>
{
User GetUserByXyz(int id);
}
public interface IUnitOfWork
{
T Respository<T>() where T : IRepository<T>;
}
公共接口IRepository
{
T GetEntity(int-id);
}
公共接口IUserRepository:IRepository
{
用户GetUserByXyz(int-id);
}
公共接口工作单元
{
T Respository(),其中T:i pository;
}
我使用Unity来解决一些引用。以下是UoW的实施情况:
public class UnitOfWork : IUnitOfWork
{
public T Respository<T>() where T : IRepository<T>
{
var container = new UnityContainer();
return container.Resolve<T>();
}
}
公共类UnitOfWork:IUnitOfWork
{
public T Respository(),其中T:i Respository
{
var container=new UnityContainer();
返回container.Resolve();
}
}
现在调用接口时遇到问题:
User user = _unitOfWork.Respository<IUserRepository>().GetUserByXyz(1);
User User=\u unitOfWork.Respository().GetUserByXyz(1);
类型“IUserRepository”不能用作中的类型参数“T”
泛型类型或方法“IUnitOfWork.Respository()”。没有
从“IUserRepository”到的隐式引用转换
“我相信”
如何避开常规约束错误?您混淆了常规约束:
public T Respository<T,U>() where T : IRepository<U>
User user = _unitOfWork.Respository<IUserRepository,User>().GetEntity(1);
public T Respository(),其中T:IRepository
User User=\u unitOfWork.Respository().GetEntity(1);
您对i工作单元的定义似乎有点奇怪,而且您的通用参数约束似乎有误:
public interface IUnitOfWork
{
T Respository<T>() where T : IRepository<T>;
}
关于我的评论:
语句public T Respository(),其中T:IRepository
表示您期望的类型本身就是一个存储库,例如,IUserRepository必须是一个IRepository
,才能满足您的条件
您需要两个不同的泛型,一个用于reportoryTItem
中保存的项目,另一个用于存储库本身TRepo
然后整个代码变成:
public interface IRepository<TItem>
{
TItem GetEntity(int id);
}
public interface IUserRepository : IRepository<User>
{
}
public interface IUnitOfWork
{
TRepo Respository<TRepo,TItem>() where TRepo : IRepository<TItm>;
}
公共接口IRepository
{
TItem-GetEntity(int-id);
}
公共接口IUserRepository:IRepository
{
}
公共接口工作单元
{
TRepo Respository(),其中TRepo:i pository;
}
及
公共类UnitOfWork:IUnitOfWork
{
public TRepo Respository()其中TRepo:i Respository
{
var container=new UnityContainer();
返回container.Resolve();
}
}
最后,调用变为:
User user = _unitOfWork.Respository<IUserRepository,User>().GetEntity(1);
User=\u unitOfWork.Respository().GetEntity(1);
初始注释:
不需要第二个类型参数的替代解决方案:
我同意@Jon Egerton的观点,要使其正确工作,一个选项是引入第二个泛型类型参数(TItem
,在TItemRepository
旁边)。但是,还有另一种解决方案涉及到标记接口IRepository
:
// non-generic marker interface (empty)
public interface IRepository {}
public interface IRepository<T> : IRepository { … /* as before */ }
// ^^^^^^^^^^^^^
// added
public class UnitOfWork
{
public TRepository Get<TRepository>() where TRepository : IRepository
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// this way, no 2nd type parameter is
// needed since the marker interface is
// non-generic.
{
return new UnityContainer().Resolve<TRespository>();
}
}
//非通用标记接口(空)
公共接口IRepository{}
公共接口IRepository:IRepository{…/*与前面一样*/}
// ^^^^^^^^^^^^^
//增加
公营单位
{
public TRepository Get()其中TRepository:IRepository
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//这样,就不需要第二个类型参数
//需要,因为标记接口是
//非泛型。
{
返回新的UnityContainer().Resolve();
}
}
根据要求:工作单元示例:
如果你跟随,你会得到与你现在所得到的完全不同的东西。更确切地说,根据他自己的理解,一个工作单元仅仅跟踪对一组对象所做的所有更改。这背后的思想是,当通过工作单元对象请求时,更改不会一次一个地持久化(例如,保存到数据库),而是同时持久化;因此,模式的名称为:
class UnitOfWork<T>
{
// the UnitOfWork object tracks changes to objects of type T:
private HashSet<T> newItems;
private HashSet<T> modifiedItems;
private HashSet<T> removedItems;
public void Commit()
{
// let's say items are persisted to an RDBMS, then:
// * generate 'DELETE FROM [tableForItemsOfTypeT]' statements
// for all items in the 'removedItems' set;
// * generate 'INSERT INTO [tableForItemsOfTypeT]' statements
// for all items in the 'newItems' set;
// * generate 'UPDATE [tableForItemsOfTypeT]' statements
// for all items in the 'modifiedItems' set.
}
}
工作单元类
{
//UnitOfWork对象跟踪对T类型对象的更改:
私有HashSet newItems;
私有哈希集修饰符;
私有HashSet-removedItems;
公共无效提交()
{
//假设项目被持久化到RDBMS,那么:
//*生成“从[tableForItemsOfTypeT]删除”语句
//对于“removedItems”集合中的所有项目;
//*生成“插入[tableForItemsOfTypeT]”语句
//对于“newItems”集合中的所有项目;
//*生成“UPDATE[tableForItemsOfTypeT]”语句
//对于“modifiedItems”集中的所有项。
}
}
IAccountRepository
来自哪里?这是上面代码示例中的一个输入错误,还是您在此处显示的代码不完整?这是一个输入错误-更新了原始帖子:)我怀疑这里有两个不同的泛型-一个是T:IRepository,一个是T:SomeOtherClass(例如User)。也许应该拆分为使用TItem和TRepo?我希望在子接口上调用该方法,例如GetUserByXyz。这就是为什么我试图将类型返回为T.Modified OP.i不确定是否滥用了工作单元模式,但使用UoW的原因是将所有存储库组合在一起,以便更容易管理对象状态。至于UoW是一个服务定位器——这部分是正确的,这就是为什么我在玩泛型并试图限制范围:)@Fixer,您只是通过提供一个“入口点”将它们按语法“分组”,从中可以要求存储库;但是真正的“分组”可能涉及组合,即在同一个类中有几个不同的IRepository
字段或属性。我明白了-你介意给我一个简单的例子吗?抱歉,我是UoW的新手(你可能会说)@Fixer:我也不是这方面的专家(但我会尝试提供一个例子);我只是看到了你的解决方案中可能存在的一个缺陷。但是如果像Repository()
这样的方法是什么呢
User user = _unitOfWork.Respository<IUserRepository,User>().GetEntity(1);
_unitOfWork.Respository<IUserRepository>()…
_unityContainer.Resolve<IUserRepository>()…
// non-generic marker interface (empty)
public interface IRepository {}
public interface IRepository<T> : IRepository { … /* as before */ }
// ^^^^^^^^^^^^^
// added
public class UnitOfWork
{
public TRepository Get<TRepository>() where TRepository : IRepository
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// this way, no 2nd type parameter is
// needed since the marker interface is
// non-generic.
{
return new UnityContainer().Resolve<TRespository>();
}
}
class UnitOfWork<T>
{
// the UnitOfWork object tracks changes to objects of type T:
private HashSet<T> newItems;
private HashSet<T> modifiedItems;
private HashSet<T> removedItems;
public void Commit()
{
// let's say items are persisted to an RDBMS, then:
// * generate 'DELETE FROM [tableForItemsOfTypeT]' statements
// for all items in the 'removedItems' set;
// * generate 'INSERT INTO [tableForItemsOfTypeT]' statements
// for all items in the 'newItems' set;
// * generate 'UPDATE [tableForItemsOfTypeT]' statements
// for all items in the 'modifiedItems' set.
}
}