实现内部接口的公共抽象类中的抽象方法会导致编译错误?

4
internal interface I_Foo
{
    void Bar();
}

public abstract class A_Foo : I_Foo
{
    public A_Foo() { }
    abstract void I_Foo.Bar();
}

public class Foo : A_Foo
{
    public Foo() : base() { }
    internal override void Bar()
    {

    }
}

你好!我想让一些方法对外部代码可见,而其他方法只对我的程序集可见。为此,我创建了一个内部接口I_Foo,作为程序集中其他部分的契约,一个公共抽象类A_Foo,用于对外部代码进行抽象,并集中一些构造函数功能,以及几个不同的Foo类,它们显式地实现了A_Foo和I_Foo以保留内部修饰符。

然而,在A_Foo类中,我得到了这样的错误信息:

'A_Foo.I_Foo.Bar()'必须声明一个主体,因为它没有标记为abstract、extern或partial

即使该方法明确标记为“抽象”,如果我添加一个主体,就会得到“抽象不是有效的修饰符”的错误信息。

我需要明确声明这个方法,以便在公共类中将其设为内部,并且我需要它是抽象的,这样我才能在实际实现Foo中重写它。

为什么编译器不允许我这样做? 还有其他方法可以实现相同的功能吗? 谢谢。


为什么方法必须是A_Foo? - Pieter Geerkens
public A_Foo() 应该改为 protected A_Foo(),对于抽象类来说这是默认值。由于抽象类的本质,它们的构造函数只能在继承的类内部使用,所以通常避免在构造函数中使用 public 修饰符(也避免使用 protected internal 的组合修饰符)。 - Jeppe Stig Nielsen
2个回答

13

显示接口实现必须具有实际的实现。这里的技巧是使其只调用一个非显式(内部)抽象方法:

public abstract class A_Foo : I_Foo
{
    // Classes outside the assembly can't derive from A_Foo
    // anyway, so let's make the constructor internal...
    internal A_Foo() { }

    void I_Foo.Bar()
    {
        Bar(); // Just delegate to the abstract method
    }

    internal abstract void Bar();
}

这仍然允许I_Foo使用内部类型等,因为Bar从未公开暴露 - 但它符合语言的其他规则。


完美、干净、可用。我会在6分钟内接受它作为答案 :) 谢谢! - Daniel
我知道这个问题中Bar也有internal,但是也许用protected更好?如果它真的需要internal,那么实例构造函数也应该是internal的,因为带有internal abstract方法的(public)类不能从另一个项目继承。 - Jeppe Stig Nielsen
@JeppeStig:有时候这正是你想要的。我们在 Noda Time 中使用了这种模式来处理 1.x 版本中的 CalendarSystem。它是一个公共抽象类型,但其他程序集不能从中派生,这是故意的。 - Jon Skeet
我同意,那很好。在这种情况下(以及您的答案中),我会确保所有实例构造函数都是“internal”(或“private”)。例如,“System.Globalization.EastAsianLunisolarCalendar”是一个(非嵌套)公共抽象类型,具有几个“internal abstract”属性和方法。如果您尝试从“mscorlib.dll”之外派生它,则会收到一堆编译时错误,其中许多显示了这些内部成员。但是,其中一个错误解释了没有可用的构造函数。那是因为他们注意到并使构造函数“internal”。 - Jeppe Stig Nielsen
@JeppeStigNielsen:将构造函数设为内部。 - Jon Skeet

3

该方法不能是抽象的。问题在于您尝试使用显式接口实现(void I_Foo.Bar)。这些方法无法后期重写 - 因此必须被实现。

如果直接声明Bar(void Bar()),则可以使其成为抽象方法。


1
不行,因为要实现接口必须将其公开,而且 OP 不希望它被公开。换句话说,这并没有解决问题背后的动机。(例如,想象一下 Bar 实际上使用了一个内部类型作为参数。) - Jon Skeet

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