Fly*_*wat 9 .net c# liskov-substitution-principle composition
假设我有这样一个类:
public sealed class Foo
{
public void Bar
{
// Do Bar Stuff
}
}
Run Code Online (Sandbox Code Playgroud)
我想扩展它以添加超出扩展方法可以做的事情....我唯一的选择是组合:
public class SuperFoo
{
private Foo _internalFoo;
public SuperFoo()
{
_internalFoo = new Foo();
}
public void Bar()
{
_internalFoo.Bar();
}
public void Baz()
{
// Do Baz Stuff
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但它还有很多工作......但是我仍遇到一个问题:
public void AcceptsAFoo(Foo a)
Run Code Online (Sandbox Code Playgroud)
我可以在这里传递一个Foo,但不是超级Foo,因为C#不知道SuperFoo确实符合Liskov替换意义......这意味着我的扩展类通过组合使用非常有限.
因此,解决它的唯一方法是希望原始的API设计者留下一个界面:
public interface IFoo
{
public Bar();
}
public sealed class Foo : IFoo
{
// etc
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以在SuperFoo上实现IFoo(因为SuperFoo已经实现了Foo,只需要更改签名).
public class SuperFoo : IFoo
Run Code Online (Sandbox Code Playgroud)
在完美的世界中,消耗Foo的方法将消耗IFoo:
public void AcceptsAFoo(IFoo a)
Run Code Online (Sandbox Code Playgroud)
现在,由于通用接口,C#理解SuperFoo和Foo之间的关系,一切都很好.
最大的问题是.NET密封了许多偶尔会很好扩展的类,而且它们通常不会实现通用接口,因此采用Foo的API方法不会接受SuperFoo,也无法添加过载.
那么,对于那里的所有作曲迷们......你如何解决这个限制?
我唯一能想到的就是公开展示内部Foo,以便你偶尔可以传递它,但这看起来很混乱.
use*_*116 14
在我开始研究自己的可重用库之前,我发现自己也在问同样的问题.很多时候,如果不需要来自实现者的模糊或神秘的调用序列,那么您最终无法扩展某些类.
在允许扩展类时,你必须要问:如果开发人员扩展了我的类,并将这个新类传递给我的库,我可以透明地使用这个新类吗?我可以在这个新课上正常工作吗?这个新课真的会表现得一样吗?
我发现大多数情况下.Net Framework中的密封类具有您不知道的某些底层需求,并且鉴于当前实现无法安全地暴露给子类.
这并不完全回答您的问题,但它提供了有关为什么不能在.Net Framework中继承所有类的见解(以及为什么您应该接受密封某些类的原因).
恐怕简短的答案是,您不能不执行所需的操作,即传递组合的实例变量。
您可以允许隐式或显式转换为该类型(其实现只是传递组合实例),但在我看来,这将是相当邪恶的。
Sixlettervariable 的答案很好,我不会重复它,但如果您指出您希望可以扩展哪些类,我们也许可以告诉您为什么他们阻止它。
| 归档时间: |
|
| 查看次数: |
1416 次 |
| 最近记录: |