无法隐藏继承的成员编译错误。

3
我正在尝试做:
public abstract class Base
{
    public abstract Task Execute(); 
}

public abstract class Concrete<T> : Base where T : class
{
    new public abstract Task<T> Execute();
}

但是出现了编译器错误:“CS0533 'Concrete.Execute()' 隐藏了继承的抽象成员 'Program.Base.Execute()'",我之前隐藏过很多成员,但从未遇到这种情况,我感到非常困惑。在 MSDN 和网络上花费了很长时间,但找不到关于这种行为的任何信息。我真的很感激任何有关此问题的见解。这里是示例代码。

虽然缺少virtual关键字,但是在new的位置使用override对我来说起作用。然而,仍然存在一个问题,当隐藏基类值时,你改变了返回类型。你需要更改名称或使子类返回一个Task值。 - undefined
@mason 我以为编译器会识别出 Concrete<T> 的定义(我在使用 IntelliSense 时看到返回类型被正确推断出来,尽管有编译器错误)。所以如果我理解你的意思正确的话,问题是当使用 new 隐藏时无法更改签名?(我有一种感觉,过去我可能做过这样的事情,但我可能记错了) - undefined
@mason 这里给你一个反例,可以通过属性更改签名:https://dotnetfiddle.net/B4IkHj 看起来问题与方法/抽象成员有关。 - undefined
@Max 谢谢你的帮助,但请看一下我对mason的评论,签名不应该需要与new相同,并且new关键字应该适用于方法和属性- https://msdn.microsoft.com/en-us/library/435f1dw2.aspx - undefined
可能相关(重复?):https://dev59.com/-WUp5IYBdhLWcg3wTGTe#15362589。特别注意的是,C#语言不允许仅通过返回类型来区分重载方法。 - undefined
@JimMischel 非常感谢你的帮助,不幸的是这并不是一个协变的情况,我很抱歉,我只是浏览了一下问题,但它没有帮到我。 - undefined
3个回答

4
问题在于基本方法是“抽象的”。从“Concrete”继承的类必须覆盖“Base.Execute()”,但它无法覆盖它,因为它被“Derived.Execute()”隐藏。因此,“Concrete”将是一个无法实现任何功能(至少不是在C#中)的“抽象”类,因此它将是无用的。所以,C#编译器不允许你写这个。
如果“Base”是一个接口,那么你可以通过使用显式接口实现来解决这个问题。但是没有像显式基类实现这样的东西,所以我认为没有办法拥有这种代码,至少不能在不重命名其中一个方法的情况下做到这一点。

我刚刚意识到这一点,回到这个标签页来说一下 - 但你说得比我好多了。我在想:如果有人将一个Concrete变量引用为Base类型,那么抽象成员将是未定义的。非常感谢。 - undefined
在C#中没有"undefined"这样的东西,因为幸运的是,C#不是JavaScript。 - undefined

1

来自MSDN:

抽象方法声明引入了一个新的虚方法,但并不提供该方法的实现。相反,非抽象派生类需要通过重写该方法来提供自己的实现。

那么,这个错误的原因是C#中抽象化的工作方式,抽象化可以被继承、实现,但不能被隐藏或替换为另一个抽象化。

此外,请考虑以下代码:

public abstract class Base
{
    public abstract Task Execute();
    public abstract Task<int> Execute();
}

这段代码无法编译,因为:

类型“Base”已经定义了一个具有相同参数类型的成员“Execute”

那么当我们将第二个方法移动到派生的抽象类中时,为什么它会起作用呢?

这个类:public class Base { public Task Execute() => null; public Task<int> Execute() => null; }与你的Base一样,无法编译通过。但是这两个类可以:`public class Base { public Task Execute() => null; }class Derived : Base { public new Task<int> Execute() => null; }`。所以你的推理部分是不正确的:这种错误可以通过将方法移动到派生类来修复。 - undefined

0
其他答案已经解释了为什么会出现这个错误。
以下是避免收到错误的方法:
public abstract class RawAbstract
{
    public Task Execute() => RawExecute(); 
    protected abstract Task RawExecute();
}

public abstract class GenericAbstract<T> : RawAbstract where T : class 
{
    protected override Task RawExecute() => Execute();
    new public abstract Task<T> Execute();
}

public abstract class GenericConcrete<T> : GenericAbstract<T> where T : class 
{
    public override Task<T> Execute() { ... }
}

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