Tag: lsp

Liskov替换原则,前提条件和抽象方法

Liskov替换原则(LSP)说: 子类型不能强化前提条件。 在C#中,我可能违反以下原则: public class A { public virtual void DoStuff(string text) { Contract.Requires(!string.IsNullOrEmpty(text)); } } public class B : A { public override void DoStuff(string text) { Contract.Requires(!string.IsNullOrEmpty(text) && text.Length > 10); } } 但是,如果A.DoStuff是一个abstract方法会发生什么: public class A { public abstract void DoStuff(string text); } public class B : A { public override void […]

C#接口实现关系只是“可以做”的关系?

今天有人告诉我,C#中的接口实现只是“Can-Do”关系,而不是“Is-A”关系。 这与我长期相信LSP(Liskov Substitution Principle)相冲突。 我一直认为所有的inheritance应该意味着“Is-A”的关系。 所以,如果接口实现只是一个“可以做”的关系。 如果有一个界面“IHuman”和“IEngineer”,并且一个类“Programmer”inheritance自“IHuman”和“IEngineer”怎么办? 当然,“程序员”是“IHuman”和“IEngineer”。 如果它只是“Can-Do”关系,是否意味着我们不能指望“程序员”实例行为在被视为IHuman并被视为IEngineer时可能会有所不同?

ReadOnlyCollection vs Liskov – 如何正确建模可变集合的不可变表示

Liskov替换原则要求子类型必须满足超类型的契约。 根据我的理解,这将导致ReadOnlyCollection违反Liskov。 ICollection的合同公开了Add和Remove操作,但只读子类型不满足此合约。 例如, IList collection = new List(); collection = new System.Collections.ObjectModel.ReadOnlyCollection(collection); collection.Add(new object()); — not supported exception 显然需要不可变的集合。 有没有关于.NET的建模方法的事情? 有什么比这更好的方法呢? IEnumerable很好地暴露了一个集合,至少看起来是不可变的。 但是,语义是非常不同的,主要是因为IEnumerable没有明确地暴露任何状态。 在我的特定情况下,我正在尝试构建一个不可变的DAG类来支持FSM 。 我显然在开始时需要AddNode / AddEdge方法,但我不希望它一旦运行就可以更改状态机。 我很难表示DAG的不可变和可变表示之间的相似性。 现在,我的设计涉及预先使用DAG Builder,然后创建一次不可变图,此时它不再可编辑。 Builder和具体的不可变DAG之间唯一的通用接口是Accept(IVisitor visitor) 。 我担心,面对可能更简单的选择,这可能是过度设计/过于抽象。 与此同时,我无法接受我可以在我的图形界面上公开可能在客户端获得特定实现时抛出NotSupportedException的方法。 处理这个问题的正确方法是什么?

这是否违反Liskov替代原则,如果是这样,我该怎么办呢?

使用案例:我正在使用数据模板将View与ViewModel相匹配。 数据模板通过检查所提供的具体类型的最派生类型来工作,并且它们不查看它提供的接口,因此我必须在没有接口的情况下执行此操作。 我在这里简化了示例并省略了NotifyPropertyChanged等,但在现实世界中,View将绑定到Text属性。 为简单起见,假设带有TextBlock的View将绑定到ReadOnlyText,带有TextBox的View将绑定到WritableText。 class ReadOnlyText { private string text = string.Empty; public string Text { get { return text; } set { OnTextSet(value); } } protected virtual void OnTextSet(string value) { throw new InvalidOperationException(“Text is readonly.”); } protected void SetText(string value) { text = value; // in reality we’d NotifyPropertyChanged in here } } […]

Liskov替代和组成

假设我有这样一个类: public sealed class Foo { public void Bar { // Do Bar Stuff } } 我想扩展它以增加扩展方法可以做的事情….我唯一的选择是组合: public class SuperFoo { private Foo _internalFoo; public SuperFoo() { _internalFoo = new Foo(); } public void Bar() { _internalFoo.Bar(); } public void Baz() { // Do Baz Stuff } } 虽然这有效,但它还有很多工作……但是我仍遇到一个问题: public void AcceptsAFoo(Foo a) 我可以在这里传递Foo,但不是超级Foo,因为C#不知道SuperFoo确实符合Liskov替换意义……这意味着我的扩展类通过组合使用非常有限。 因此,解决它的唯一方法是希望原始的API设计者留下一个界面: […]

C#返回类型协方差和Liskov替换原理

我正在尝试理解协方差和LSP。 从这个问题我可以看出C#不支持返回类型协方差。 然而Liskov替换原则对返回类型强加协方差。 这是否意味着在C#中应用这个原则是不可能的? 还是我想念一些东西?