用于声明抽象泛型类型变量的 C# 语法

发布于 2024-07-18 08:13:31 字数 1175 浏览 4 评论 0原文

我有一个类定义如下;

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苦行僧 2024-07-25 08:13:31

如果我正确理解您的问题,您需要添加第三个通用参数,即存储库类型,它被限制为具有适当参数类型的 Repository 的后代。

进一步概述一下:

public abstract class Repository<TEntity,TDataContext>
    where TEntity : class
    where TDataContext : DataContext, new() {}

public abstract class BusinessObject<TEntity,TDataContext,TRepository>
    where TEntity : class
    where TDataContext : DataContext, new()
    where TRepository : Repository<TEntity,TDataContext>
{
    TRepository _repository;
}

public class ConcreteObject : BusinessObject<LSTableClass,LSDataContext,ConcreteRepo>
{ // ...

我知道它可能没有你想要的那么紧凑,但是有效地减少这种情况但仍然保留强类型所需要的是高阶泛型类型(在 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:

public abstract class Repository<TEntity,TDataContext>
    where TEntity : class
    where TDataContext : DataContext, new() {}

public abstract class BusinessObject<TEntity,TDataContext,TRepository>
    where TEntity : class
    where TDataContext : DataContext, new()
    where TRepository : Repository<TEntity,TDataContext>
{
    TRepository _repository;
}

public class ConcreteObject : BusinessObject<LSTableClass,LSDataContext,ConcreteRepo>
{ // ...

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.

ゃ人海孤独症 2024-07-25 08:13:31

由于您对其施加的限制,您的声明

protected Repository<Object, DataContext> _repository;

不起作用:

...    
where TDataContext : DataContext, new()

特别是 new() 部分。

我猜您想“注入”一个满足您的通用接口的对象。

有两件事:

  • 您无法在 RepositoryRepository 之间进行转换。 。这称为逆变/协方差,直到 C# 4 才可用。在 C# 3 中,这是两种完全不同的类型。

  • 如果要在类中存储泛型成员,则类型参数要么必须是具体类型,要么必须在父类声明中将它们声明为类型参数(使得

选项:

  • 在父类上使用泛型类型参数。
  • 从类声明中删除 new() 约束。

Your declaration

protected Repository<Object, DataContext> _repository;

Didn't work because of the constraint you placed upon it:

...    
where TDataContext : DataContext, new()

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> and Repository<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:

  • Use generic type arguments on your parent class.
  • Remove the new() constraint from your class declaration.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文