C#泛型下界约束“其中MySubClass:T”(java的“超级”)

我想知道C#是否具有
Java的< X super MySubClass>通用约束.

为了指定上限,可以使用类Foo< T>.其中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;
    }
}

>在接口上使用variance,但我不确定这是否可用于指定泛型参数的下限.

最佳答案 我刚遇到同样的问题.选项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被操作“访问”:

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成员

点赞