用于声明抽象泛型类型变量的 C# 语法
我有一个类定义如下;
public abstract class Repository<TEntity, TDataContext> : DisposableBaseClass
where TEntity : class
where TDataContext : DataContext, new()
{...contains Linq to SQL related functionality
在具体的子类中,我这样定义类型;
public class ConcreteRepo : Repository<LSTableClass, LSDataContext>
在下一层,我有将存储库对象保存为私有变量的业务对象。
这很好;
private ConcreteRepo _repository;
但是,然后我将其重构为所有业务对象的父类 - 该父类保存存储库/实现 Dispose 模式来处理存储库等。
我的问题是我无法获得正确的语法来声明变量。
我最接近的是;
protected Repository<Object, DataContext> _repository;
但这会出现编译错误:
“错误 1 'System.Data.Linq.DataContext' 必须是具有公共无参数构造函数的非抽象类型,才能将其用作泛型类型或方法中的参数 'TDataContext' '....存储库'...”
我尝试过各种其他方法,但遇到了其他问题。
在继承这个抽象类的业务层对象中,我创建并使用 _repository 变量进行强制转换;
(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo();
- 我认为这会很好,假设我可以在父级中正确获得此声明。
如果我不能让它工作,我必须在每个业务对象中声明 _repository,并提供完整/具体的类型详细信息,并在每个业务对象中实现处置模式以进行清理。 不是世界末日,但我不想这样。
I have a class defined as follows;
public abstract class Repository<TEntity, TDataContext> : DisposableBaseClass
where TEntity : class
where TDataContext : DataContext, new()
{...contains Linq to SQL related functionality
In the concrete sub-class I define the types as so;
public class ConcreteRepo : Repository<LSTableClass, LSDataContext>
At the next tier up, I have business objects which hold the Repository object as a private variable.
This was fine;
private ConcreteRepo _repository;
However, I then refactored this out into a parent class for all the business objects - this parent class holds the repository/ implements Dispose pattern to dispose of repository etc.
My problem is that I just can't get the syntax right for the declaration of the variable.
The closest I have come is;
protected Repository<Object, DataContext> _repository;
but this gives the compile error:
"Error 1 'System.Data.Linq.DataContext' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TDataContext' in the generic type or method '....Repository'..."
I've tried various other things but hit other problems.
In the business layer object inheriting this abstract class I am creating and using the _repository variable with a cast;
(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo();
- and I think this will be fine, assuming I can get this declaration right in the parent.
If I can't get this to work I have to declare the _repository in each business object, with the full/ concrete type details, and implement the dispose pattern in each one to clear up. Not the end of the world, but I'd like to not have to.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果我正确理解您的问题,您需要添加第三个通用参数,即存储库类型,它被限制为具有适当参数类型的
Repository
的后代。进一步概述一下:
我知道它可能没有你想要的那么紧凑,但是有效地减少这种情况但仍然保留强类型所需要的是高阶泛型类型(在 Haskell 中称为类型类):一种指示的方式该类型参数本身是通用的,并且可以采用类型参数。
If I understand your problem correctly, you need to add a third generic parameter, the repository type, which is constrained to be a descendant of
Repository
with the appropriate argument types.To outline it some more:
I know it's probably not as compact as you would like, but what's needed to reduce this down effectively yet still retain the strong typing, is higher order generic types (called type classes in Haskell): a way of indicating that type parameters are themselves generic, and can take type parameters.
由于您对其施加的限制,您的声明
不起作用:
特别是
new()
部分。我猜您想“注入”一个满足您的通用接口的对象。
有两件事:
您无法在
Repository
和Repository
之间进行转换。 。这称为逆变/协方差,直到 C# 4 才可用。在 C# 3 中,这是两种完全不同的类型。如果要在类中存储泛型成员,则类型参数要么必须是具体类型,要么必须在父类声明中将它们声明为类型参数(使得
选项:
Your declaration
Didn't work because of the constraint you placed upon it:
Specifically the
new()
part.I'm guessing that you want to 'inject' an object satisfying your generic interface.
Two things:
You can't convert between
Repository<Object, DataContext>
andRepository<LSTableClass, LSDataContext>
. Not with C# 3. This is called Contravariance/Covariance and won't be available until C# 4. In C# 3 these are two completely different types.If you want to store a generic member inside of a class, then the type arguments either have to be concrete types, or they must be declared as type parameters in the parent class declaration (making that generic).
Options: