c# - 使用分部类实现分层接口(interface)以提高可读性

标签 c#

我知道我们可以使用部分类来分离接口(interface)的实现,这样它更有条理,更易读。

但是,如果我正在实现的接口(interface)继承了其他接口(interface),如下所示:

public interface IA
{
    void DoA();
}
public interface IB : IA
{
    void DoB();
}
public partial class B : IB
{
    public void DoB() { }
}
public partial class B : IA
{
    public void DoA() { }
}

这和这样做是一样的:

public class B : IB, IA { // ... }

编译器允许这样做,但我不确定这是否会给我带来麻烦。有人可以澄清它是否会引起问题。

我正在考虑这样做并使用注释,但如果不会引起任何问题,我宁愿采用上述方法:

public partial class B : IB
{
    public void DoB() { }
}
public partial class B // IA Implementation
{
    public void DoA() { }
}

编辑

如果我这样做,编译器会提示“'IA' 已经在接口(interface)列表中列出。”:

public class B : IA, IA
{
}

但它会允许这样做:

public class B : IB, IA { // ... }

如果 IB 继承 IA 为什么会允许它。显然这两种情况是不同的,因为编译器允许一种情况而不允许另一种情况。一定是有原因的。

最佳答案

The compiler allows that but I am not sure if that will get me in trouble. Can someone please clarify if it will cause issues.

大多数时候这是一种合理的做法。我经常使用部分类来分离出一个接口(interface)实现,或者一个嵌套类的实现,你应该很有信心这样做。

但是,在一种情况下,您可能会对您描述的显式调用已实现接口(interface)的做法感到惊讶,那就是接口(interface)重新实现规则 .

最好用一个小例子来描述。假设你有

interface I { void Foo(); }
// B does not implement I.
class B { public void Foo() {} }
class C : B, I { }

这是完全合法的。 C 实现了 I,这意味着 C 必须有方法 Foo,而 C 确实有方法 Foo;它从 B 继承了它。

现在考虑:

// D implements I because D derives from C
class D : C { public new void Foo() {} }
// The I is unnecessary here, right? Or is it?
class E : D, I { }

接口(interface)重实现规则是:因为E明确的说自己实现了I,所以编译器重新做分析,判断Foo是哪个方法匹配I.Foo。总结:

  • ((I)(new C())).Foo() 调用 B.Foo
  • ((I)(new D())).Foo() 调用 B.Foo
  • ((I)(new E())).Foo() 调用 D.Foo

这可能会令人惊讶,并且当您不必要地声明接口(interface)时,它可能会意外发生。它几乎从未发生过,即使发生也几乎无关紧要,但您提出了任何可能的问题,这就是这种情况。

现在让我们考虑您的后续问题:

Clearly the two scenarios are different since the compiler allows one and not the other. There must be a reason.

正如我们已经看到的,C# 的设计者想要一种方式来表达“我引入了一个我想绑定(bind)到接口(interface)成员的新成员”,他们做出的有点模糊的选择是允许这种冗余声明意思是“现在重新绑定(bind)”。

但是,还有另一个设计原因允许这种冗余,而且,当它发生时发出警告。

在考虑奇怪的 C# 设计决策时,一个好的做法是记住 C# 的设计者一直明确地担心版本化软件中的内容更改。特别是,他们担心许多不同形式的“脆弱的基类故障”。这是一种失败模式,其中有人对基类进行了完全合理的更改,然后导致派生类出人意料地崩溃或行为异常。

例如考虑这一系列事件。首先,开发者 X 写道:

interface IA { void Foo(); }

然后开发者 Y 写

class C { public void Foo() {} }

然后开发者 Z 写道:

class D : C, IA { }

然后开发者 Y 意识到,哦,我实现了 IA 的契约(Contract),我可以免费获得它,并将类 C 更改为

class C : IA { }

那么现在的问题是:编译器是否应该对类 D 发出冗余警告?答案是否定的,D 类的作者没有做错任何事情,不应该让他去解决实际上不存在的问题。

这就是为什么 C# 对冗余的容忍度很高,尽管不幸的是它并不总是容忍。 (例如,重新声明通用约束是非法的,但在我看来应该是允许的。)

简而言之,任何时候您认为“C# 可能会告诉我这种冗余”时问问自己如果它是由其他人做出我无法控制的更改引起的怎么办?会不会是烦人还是有帮助?如果烦人,语言设计可能故意抑制警告。

关于c# - 使用分部类实现分层接口(interface)以提高可读性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58574977/

相关文章:

c# - 用于创建页面链接的 HTML Helper - 试图理解

c# - 为什么 WinDbg 将 System.Int32 变量显示为 24 个字节?

c# - 更改日期格式

c# - 在 C# 中执行 Oracle 解释计划

C#:更改事件目录用户密码时出现代码错误

c# - 为什么这不会产生溢出异常?

c# - 您可以在 WCF 服务下运行 WebBrowser 吗?

c# - Azure 表存储查询结果中的空值

c# - Fleck - 从服务器发送数据

c# - EpiServer - 我如何才能知道某个 block 是否正在任何已发布的页面上使用?