2

在使用 C# 泛型约束时,我对某些要求感到沮丧,我想知道是否有办法解决我的问题。如果没有,我想解释一下为什么事情没有按照我想要的方式工作。

这个例子展示了我目前基本上要做的事情:

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity, TID>
    where TEntity : EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class ServiceBase<TLogic, TEntity, TID>
    where TLogic : LogicBase<TEntity, TID>
    where TEntity : EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity, long> {}
public class EgService : ServiceBase<EgLogic, EgEntity, long> {}

提案 A显示了我希望得到的东西(我看不出它不能以这种方式工作的原因):

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity>
    where TEntity : EntityBase<?>  // why not allow some kind of a "this could be whatever" syntax here ("?"), then infer the constraints on "?" based on the definition of EntityBase<>
{ }

public abstract class ServiceBase<TLogic>
    where TLogic : LogicBase<?>  // infer the constraints on "?" based on the definition of LogicBase<>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity> {}
public class EgService : ServiceBase<EgLogic> {}

提案 B展示了另一种可能的选择,尽管不如提案 A 有吸引力:

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity>
    where TEntity : EntityBase<TID>  // introduce TID here to keep it out of class signature
    where TID : struct, IEquatable<TID>
{ }

public abstract class ServiceBase<TLogic>
    where TLogic : LogicBase<TEntity>  // introduce TEntity here
    where TEntity : EntityBase<TID>  // introduce TID here
    where TID : struct, IEquatable<TID>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity> {}
public class EgService : ServiceBase<EgLogic> {}

这两个提案都将最小化我在创建派生类型时必须指定的类型参数的数量,并且提案 A 将消除对一堆冗余约束的需要。

那么 C# 不能/不应该为这些提案之一提供支持是否有原因?(或者我是否忽略了该语言的相关现有功能?)

4

2 回答 2

2

这就是 C# 的基本方式。就允许您对类型施加的限制而言,在哪里存在一些限制。

一般来说,该where子句的大多数选项都与添加此限制将允许您对泛型类中的对象执行某些操作有关,这取决于所使用的泛型类型(例如:通过告诉它TID是一个IEquatable<TID>,您可以使用 TID好像它后来是一个 IEquatable)。逻辑是,如果您不以任何方式依赖该功能,那么实际上您的班级没有理由需要限制(尽管我承认为了清洁起见它可能很好)。

当涉及到所需LogicBase<?>的 时,已经提出了一个非常复杂的难题,就您现在可以用这个对象做什么。当您在ServiceBase<TLogic>其中定义了 TLogic LogicBase<?>时,LogicBase 的哪些功能实际上可以使用?

如果您希望获得一些不依赖于知道它的泛型类型的功能子集,那么我想说的是,您实际上需要定义一个Interface甚至只是abstract class定义ServiceBase<TLogic>不依赖于数据类型TLogic并限制你ServiceBase<TLogic>的 'sTLogic是这种新类型。因为这实际上是您要求应用程序为您推断的内容(表示 a 的组件的接口,其LogicBase<?>本质上并不依赖于它的泛型类型)。

因此,尽管理论上编译器可以以这种方式解释这一点,并在不参考对象数据类型的情况下制定出所需的约束强制和对象可用接口,但它在继承设置的复杂性和我的个人的想法是,简单地声明一个接口将是一种更有条理的方式来处理这个问题。

于 2012-07-02T07:35:30.513 回答
0

为什么不定义一个接口 IEntityBase 并使 LogicBase 和 ServiceBase 只依赖于这个接口。这将使您能够摆脱 TEntity 类型参数。

于 2012-07-02T07:49:12.653 回答