C#: 使用类泛型参数重写泛型方法

4
为什么这不可能?
abstract class A
{
    public abstract T f<T>();
}

class B<T> : A
{
    public override T f()
    {
        return default (T);
    }
}

错误:

does not implement inherited abstract member 'A.f<T>()'
no suitable method found to override

我知道签名必须相同,但从我的角度来看,我没有看到任何可能导致禁止的原因。此外,我知道另一种解决方案是将A泛型化,而不是它的方法,但由于某些原因,这对我来说不太合适。
5个回答

5
这是不可能的,因为这些方法有不同的签名。 A.f 是一个通用方法,而 B.f 不是(它仅使用类通用参数)。
您可以从调用者的角度来看到这一点:
A variableA = new A();
variableA.f<int>();

B<int> variableB = new B<int>();
variableB.f();

我知道签名不同。但是如果我在创建时指定通用参数而不是在调用方法时指定,那么它不是相同的吗? 我这样看:T A.f() == T B.f() - 两种方法都使用相同的参数,并返回相同的类型,那么我错过了什么问题? - Zoka
不,不是这样的。您可以轻松地声明包含通用方法的通用类。您正在质疑C#的设计,您有两个选择:接受它或更改语言。 - Rafal

4

B没有履行A的契约。

A允许使用任何类型参数调用f并返回该类型。 B不允许使用类型参数调用f,仅返回B的类型参数的类型。

例如,假设您有一个B<int>并将其转换为A(应该可以,因为它继承自A)。 然后您在其上调用f<bool>()(应该可以,因为它是A)。 那么接下来呢?底层的B<int>没有可调用的方法。

B b = new B<int>();
// This is legal as B inherits from A
A a = b;
// This is a legal call, but how does b handle it?
bool result = a.f<bool>();

B 只允许使用 B 的类型参数调用 f。 B 根本没有通用的方法 f,所以 B 不允许使用 B 的类型参数调用 f。 - Rune FS
很棒的答案...我认为这是最好的解释原因。 - Zoka

1

就你的代码而言

abstract class A
{
    public abstract T f<T>();
}

class B<T> : A
{
    public override T f()
    {
        return default (T);
    }
}

在下面的代码中,您希望被称为什么?
public void Foo(A myObj) {
    myObj.f<DateTime>();
}
Foo(new B<int>());

虽然类型契约(抽象类A)明确指出需要实现,但该方法没有实现。因此,您可以实现该方法或更改契约以在类级别使用类型参数。

abstract class A<T>
{
    public abstract T f();
}

class B<T> : A<T>
{
    public override T f()
    {
        return default (T);
    }
}

代码可以编译,但它也会限制函数 f 的执行。


1
@Zoka你说得对 “_对于所有它的函数_” 。但是f<T>是基类的函数,而派生类类型参数对其没有影响。这是基类方法的类型参数 - 方法级别,不是类级别。 - horgh
现在...Rune FS的最后一个例子在这里:我可以为类和覆盖命名相同的通用参数,并且它确实编译,但是它会做什么呢?我的猜测是它只是隐藏了类参数,使其无法在重写方法中使用,对吗? - Zoka
1
@Zoka,这是一样的,就像你有不同的名称一样,即使在调用f<anything>();时仍然可以指定任何类型参数,并且它将使用调用指定的类型参数,而不是类类型参数。 - horgh
@Konstantin:我也这么想。 - Zoka
@Zoka 我已经更新了示例,希望能更清楚地说明为什么你的论点不成立。类型系统允许您将任何A用作上述方法的参数(并且由于B派生自A,因此任何B也是A)。编译器需要能够保证您可以将B作为该方法的参数传递,并且为了能够做到这一点,它需要保证B.f<DateTime>()是有效的。 - Rune FS
显示剩余2条评论

0

可能这就是你想要做的:

abstract class A
{
    public abstract T f<T>();
}

class B<U> : A
{
    public override T f<T>() //also needs to have a generic type parameter
    {
        throw new NotImplementedException();
    }

    public U f()
    {
        return f<U>();
    }
}

通用方法类型参数和通用类类型参数(这里是TU)没有直接的联系,即T在基类中不受限于成为U(或其他内容),您无法在派生类中更改此限制。


0
abstract class A
{
    public abstract T f<T>();
}

class B<T> : A
{
    public override T f<T>()
    {
        return default (T);
    }
}

我知道解决方案,我想知道为什么? - Zoka
这是正确的方法,问题与“我无法将方法public abstract void Func()覆盖为public override bool Func(int digit),为什么?”相同,签名不匹配。 - burning_LEGION

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接