我想知道C#是否与Java的<X super MySubClass>
通用约束相当。
要指定上限,可以使用class Foo<T> where T : MySuperClass { ... }
,但是如何指定泛型参数的下限?
有一些方法可以获得类似的结果,但我还没有找到完美的东西:
使用第二个通用参数 - 但调用者可以指定实际下限的子类。
public class Foo<T, TLowerBound>
where TLowerBound : MySubClass
where TLowerBound : T
{
...
}
这有时用于扩展方法,因此扩展方法的参数U
被约束为类'参数T
的超类。
public static class Extensions {
public static void Method<T, U>(this Foo<T> self, U someU) where T : U {
self.ValueOfTypeT = someU;
}
}
在接口上使用差异,但我不确定这是否可用于指定泛型参数的下限。
答案 0 :(得分:2)
我刚遇到同样的问题。选项2(使用扩展方法)非常有效,直到您需要下限为虚拟的方法(因此根据对象的动态类型调度)。如果您需要,这是一个可行的解决方案,使用选项3(接口方差,加上众所周知的访客模式)。
为了达到相当于
的目的public class A<T> // an argument to the generic method
{
}
public class B<S>
{
public virtual R Fun<T>(A<T> arg) where S : T // illegal in C#/CLR
{
...
}
}
public class C<S> : B<S>
{
public override R Fun<T>(A<T> arg)
{
}
}
您执行以下操作。首先,为要执行的操作定义一个接口(我们将在这里使用访问者模式,因此每个类型必须有一个单独的方法覆盖Fun
):
public interface IFun<in T>
{
R Fun<S>(B<S> self) where S : T;
R Fun<S>(C<S> self) where S : T;
}
注意,泛型参数T
仅用作约束,因此接口可以是逆变量。我们现在使用此功能,让B
和C
访问&#34;通过操作:
public class B<S>
{
public virtual R Perform(IFun<S> fun)
// contravariant, any IFun<T> with S : T will be accepted
{
return fun.Fun(this);
}
}
public class C<S> : B<S>
{
public override R Perform(IFun<S> fun)
{
return fun.Fun(this);
}
}
为了使用参数A<T>
实际执行操作,将它包装在实现接口的struct / class中:
public struct TheFun<T> : IFun<T>
{
public A<T> arg;
R IFun<T>.Fun<S>(B<S> self)
{
... body of B<S>.Fun(A<T> arg) ...
}
R IFun<T>.Fun<S>(C<S> self)
{
... body of C<S>.Fun(A<T> arg) ...
}
}
要关闭,请引入扩展方法,如选项2:
public static class Extensions
{
public static R Fun<S,T>(this B<S> self, A<T> arg) where S : T
{
return self.Perform(new TheFun<T> { arg = arg });
}
}
完成。它工作,没有一个演员或类型检查。主要缺点是:
B
和C
移至TheFun
,因此必须使B
和C
所需的所有成员都可以访问