我知道我们可以使用部分类来分隔接口的实现,因此它更加有条理和可读性。
但是,如果我要实现的接口继承了其他接口,例如:
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() { }
}
Run Code Online (Sandbox Code Playgroud)
这与执行此操作相同:
public class B : IB, IA { // ... }
Run Code Online (Sandbox Code Playgroud)
编译器允许这样做,但是我不确定这是否会给我带来麻烦。有人可以澄清是否会引起问题。
我正在考虑改为执行此操作并使用注释,但是如果不引起任何问题,我宁愿采用上述方法:
public partial class B : IB
{
public void DoB() { }
}
public partial class B // IA Implementation
{
public void DoA() { }
}
Run Code Online (Sandbox Code Playgroud)
编辑
如果我在下面这样做,编译器会抱怨“'IA'已经在接口列表中列出了”。
public class B : IA, IA
{
}
Run Code Online (Sandbox Code Playgroud)
但这将允许:
public class B : IB, IA { // ... }
Run Code Online (Sandbox Code Playgroud)
如果IB继承,为什么会允许它IA。显然,这两种情况是不同的,因为编译器允许一种情况,而不允许另一种情况。一定是有原因的。
编译器允许这样做,但是我不确定这是否会给我带来麻烦。有人可以澄清是否会引起问题。
在大多数情况下,这是一种合理的做法。我经常使用部分类来分离接口实现或嵌套类的实现,您应该对此充满信心。
但是,在一种情况下,您描述的显式调出已实现的接口的做法可能会让您感到惊讶,这就是接口重新实现规则。
最好用一个小例子来描述。假设你有
interface I { void Foo(); }
// B does not implement I.
class B { public void Foo() {} }
class C : B, I { }
Run Code Online (Sandbox Code Playgroud)
那是完全合法的。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 { }
Run Code Online (Sandbox Code Playgroud)
接口重新实现的规则是:因为E明确表示它实现了I,所以编译器将重新进行分析以确定Foo与I.Foo匹配的方法。加起来:
((I)(new C())).Foo() 来电 B.Foo((I)(new D())).Foo() 来电 B.Foo((I)(new E())).Foo() 来电 D.Foo这可能令人惊讶,并且在不必要地声明接口时可能会意外发生。它几乎永远不会发生,并且几乎什么时候都不会发生,但是您要求任何可能的问题,这就是这种情况。
现在让我们考虑您的后续问题:
显然,这两种情况是不同的,因为编译器允许一种情况,而不允许另一种情况。一定是有原因的。
正如我们已经看到的,C#的设计师想要一种表达“我已经引入了一个我想绑定到接口成员的新成员”的方式,而他们做出的模糊选择是允许这个多余的声明表示“立即重新绑定”。
但是,还有另一个设计原因是允许这种冗余,并且在发生冗余时不对其进行警告。
考虑奇异的C#设计决策时,一种好的做法是记住C#的设计人员始终时刻担心版本软件中的内容更改。他们尤其担心“脆性基类故障”的许多不同形式。那是失败模式,在此模式下,某人进行了对基类完全合理的更改,然后导致派生类意外中断或表现异常。
例如考虑该事件序列。首先,开发人员X写道:
interface IA { void Foo(); }
Run Code Online (Sandbox Code Playgroud)
然后开发者Y写道
class C { public void Foo() {} }
Run Code Online (Sandbox Code Playgroud)
然后开发人员Z写道:
class D : C, IA { }
Run Code Online (Sandbox Code Playgroud)
然后开发人员Y意识到,哦,我实施了IA的合同,我可以免费获得它,并将C类更改为
class C : IA { }
Run Code Online (Sandbox Code Playgroud)
因此,现在的问题是:编译器是否应在类D上给出冗余警告?答案是否定的,D类的作者没有做错任何事情,因此不应致力于解决实际上不存在的问题。
这就是C#倾向于容忍冗余的原因,尽管不幸的是,它并不总是能够容忍的。(例如,重述通用约束是非法的,但我认为应该允许。)
简而言之,任何时候您以为“ C#可能会告诉我有关此冗余的内容”时,请问自己这是否由其他人做出了我无法控制的更改导致?这会很烦人还是有帮助?如果令人讨厌,语言设计可能会故意抑制警告。
| 归档时间: |
|
| 查看次数: |
269 次 |
| 最近记录: |