C# 使用约束泛型仅允许在父类型上运行函数

标签 c# generics inheritance type-constraints

我尝试使用泛型约束来仅允许在另一种类型的父类型上调用泛型函数。

示例:

public class SomeClass<Derived> 
    where Derived : class
{
    public void call<Parent>()
        where Parent : class
    {
        ParenthoodChecker<Derived, Parent> checker =
            new ParenthoodChecker<Derived, Parent>();
    }
}

public class ParenthoodChecker<Derived, Parent> 
    where Parent  : class 
    where Derived : Parent
{
    public ParenthoodChecker()
    {
    }
}

目前,我收到以下错误消息:

Error CS0311: The type 'Derived' cannot be used as type parameter 'Derived' in the generic type or method 'ParenthoodChecker'. There is no implicit reference conversion from 'Derived' to 'Parent'. (CS0311)

有没有办法在编译时强制执行这样的事情?我不想在运行时检查,我觉得编译器应该能够推断出这一点。

最佳答案

您面临的问题是通用约束(where 关键字)仅与使用它的类/方法的通用参数相关联。因此,在编写泛型方法call<Parent>时,约束只能在参数 Parent 上定义.

您可以通过向方法添加新的人工通用参数来解决该问题 - 这会使签名复杂化,但从语法的角度来看最终会使其正确:

public class SomeClass<Derived>
    where Derived : class
{
    public void call<Parent, NewDerived>()
        where Parent : class
        where NewDerived: Derived, Parent
    {
        ParenthoodChecker<NewDerived, Parent> checker =
            new ParenthoodChecker<NewDerived, Parent>();
    }
}

我认为,除了丑陋之外,除了增加复杂性之外,这个解决方案不会导致不正确的行为。 NewDerived类型仍然是Derived .

从更高的理论基础来看,这是比较值的问题:if A > BA > C ,我们可以说 B > C ? - 显然不是因为 B 之间的精确关系和C此处不再赘述。

相反,如果你说Parent > NewDerivedDerived > NewDerived ,那就可以了。但你仍然缺乏 Parent > Derived 的证据。这就是为什么(我认为)不可能编写这样的函数来让编译器认为 Parent 的全部原因。实际上是 Derived 的父类(super class)型.

通过上面给出的实现,您甚至可以自由地使用 Derived 调用该方法。代替NewDerived :

class A { }
class B : A { }

SomeClass<B> s = new SomeClass<B>();
s.call<A, B>();

在此示例中,只有两个类, AB ,所以甚至没有任何其他类来扮演虚构的角色NewDerived 。整个操作保持在类型 A 之间(作为基础)和B (作为派生)。

关于C# 使用约束泛型仅允许在父类型上运行函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49026828/

相关文章:

c# - 添加具有不同程序集的迁移

c# - 将 LuisDialog 方法 (LuisIntents) 拆分为多个文件或类别

c# - C# 中的蓝牙 GUID

java - 在函数中使用泛型的问题

php - 我如何在 PHP 中访问类实例的父级?

c# - 搜索 IP 范围 - 算法/数据结构?

java - 修复通用类型使用的警告消息

java - 为什么 Java 8 泛型类型推断选择这个重载?

java - Hibernate - 强制父类和子类之间的内部连接

java - 如何使用扩展 Room 中另一个类的实体类?