我尝试使用泛型约束来仅允许在另一种类型的父类型上调用泛型函数。
示例:
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 > B
和A > C
,我们可以说 B > C
? - 显然不是因为 B
之间的精确关系和C
此处不再赘述。
相反,如果你说Parent > NewDerived
和Derived > NewDerived
,那就可以了。但你仍然缺乏 Parent > Derived
的证据。这就是为什么(我认为)不可能编写这样的函数来让编译器认为 Parent
的全部原因。实际上是 Derived
的父类(super class)型.
通过上面给出的实现,您甚至可以自由地使用 Derived
调用该方法。代替NewDerived
:
class A { }
class B : A { }
SomeClass<B> s = new SomeClass<B>();
s.call<A, B>();
在此示例中,只有两个类, A
和B
,所以甚至没有任何其他类来扮演虚构的角色NewDerived
。整个操作保持在类型 A
之间(作为基础)和B
(作为派生)。
关于C# 使用约束泛型仅允许在父类型上运行函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49026828/