C#泛型约束:类上的类型参数继承方法的类型参数?

Tom*_*han 5 c# generics

我有一个泛型类,我在其上定义了一个方法,该方法应该接受另一个类型的参数,但仅当另一个类型实现类的类型参数时.但是,这不会编译:

class GenericClass<TClass>
{
    public void DoSomething<TMethod>(TMethod input) where TClass : TMethod
    {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

TClass在方法的约束中遇到编译器错误.有没有其他方法来指定这个?

澄清:
我的印象是,在TMethod : TClass意味着TMethod必须继承或实现TClass(这取决于是否TClass是一个具体类型或接口).在其他,略有不同寻常的符号TMethod > TClass(意思TMethod是超集TClass).

我想要的是,TMethod如果TClass继承或实现它,它应该只是一个有效的类型,即TClass > TMethod.请问TMethod : TClass这样做呢?

(一个答案国家的TMethod : TClass要求TMethod从分配的 TClass.我不知道如果这符合我的要求,但如果这样做,请更详细地解释什么是从分配的手段,因为如果它可以帮助我我可能误解它...)

Eri*_*ert 8

执行摘要:

Chris Hannon的答案基本上是正确的.但是,有一些涉及接口和扩展方法的偷偷摸摸的技巧可能会让你得到你想要的.

过多的细节:

我们偶尔会被问到这种约束,还有其他语言有这样的约束.Java和我相信Scala都有办法说"这必须是一种超类型".正如其他人所指出的那样,这种约束无法在C#类型系统或底层CLR类型系统中表示.

你可能想要这种方差的原因是这样的情况:

class ImmutableStack<T>
{
    public static ImmutableStack<T> Empty { get { return empty; } }
    private static ImmutableStack<T> empty = new ImmutableStack<T>();
    private T head;
    private ImmutableStack<T> tail;
    public ImmutableStack<T> Pop()
    {
        if (this == empty) throw new Exception();
        return this.tail;
    }
    public ImmutableStack<N> Push(N value) where T : N // not legal
    {
        var result = new ImmutableStack<N>();
        result.head = value;
        result.tail = this; // also not legal
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

Tiger tony = new Tiger();
Elephant dumbo = new Elephant();
ImmutableStack<Tiger> tigers = ImmutableStack<Tiger>.Empty;
tigers = tigers.Push<Tiger>(tony);
ImmutableStack<Mammal> mammals = tigers.Push<Mammal>(dumbo);
Run Code Online (Sandbox Code Playgroud)

嘿,现在你可以将大象推到一堆老虎身上,神奇地变成了一堆哺乳动物!

这在C#中是不可能的,因为我在这里显示有两个原因:第一,因为没有这样的泛型约束,第二,因为不可变类类型不是协变的.(尾部的赋值需要协方差.)

但是,如果您偷偷摸摸,可以在C#中执行此操作.您可以通过将所有内容表示为协变接口而不是类来解决协方差问题.您可以通过将相关方法从正确的类中移出并将其作为扩展方法来解决"无此约束"问题!我举一个如何这样做的例子:

http://blogs.msdn.com/b/ericlippert/archive/2007/12/06/immutability-in-c-part-three-a-covariant-immutable-stack.aspx