gpt4 book ai didi

c# - Liskov 替换原则和接口(interface)

转载 作者:行者123 更新时间:2023-11-30 19:54:04 24 4
gpt4 key购买 nike

ICollection<T>.Add() - 数组的实现打破了 Liskov 替换原则?该方法导致 NotSupportedException ,这确实打破了 LSP,恕我直言。

string[] data = new string[] {"a"};
ICollection<string> dataCollection = data;
dataCollection.Add("b");

这导致

Unhandled exception: System.NotSupportedException: Collection was of a fixed size.

我发现了一个关于 Stream 的非常相似的问题-实现。我打开一个单独的问题,因为这种情况非常不同:Liskov substitution principle and Streams .这里的区别在于 ICollection不提供 CanAdd -属性(property)或类似的东西,如Stream -类确实如此。

最佳答案

我明白你为什么会这么想。有一个函数需要一个集合,并且它希望它是可修改的。传递一个数组会使它失败,所以很明显你不能用这个特定的实现来代替接口(interface),对吧?

有问题吗?或许。这取决于您期望理想能够实现的频率。您是否会不小心使用数组而不是集合,然后在十年后对它崩溃感到惊讶?并不真地。 .NET 应用程序使用的类型系统并不完美 - 它不会告诉您这个特定的 ICollection<T>用法要求集合是可修改的。

如果数组不假装实现 ICollection<T>,.NET 会更好吗? (或 IEnumerable<T> ,他们也没有“真正”实现)?我不这么认为。有没有办法保持数组“存在”的便利性 ICollection<T>那也可以避免同样的 LSP 违规?没有。底层数组仍将是固定长度的 - 充其量,您会违反更有用的原则(例如引用类型不应具有引用透明性这一事实)。

但是等等!来看实际契约(Contract)ICollection<T>.Add .它是否允许 NotSupportedException被扔?哦是的 - 引用 MSDN:

[NotSupportedException is thrown if ...] The ICollection is read-only.

当您查询 IsReadOnly 时,数组会返回 true .契约(Contract)得到维护。

如果你考虑Stream不要因为 CanWrite 而破坏 LSP ,您必须将数组视为有效集合,因为它们有 IsReadOnly , 它是 true .如果一个函数接受一个只读集合并尝试向它添加内容,则它是函数中的一个错误。没有办法在 C#/.NET 中明确指定这一点,因此您必须依赖契约(Contract)的其他部分而不仅仅是类型 - 例如该函数的文档应指定 NotSupportedException (或 ArgumentException 或其他)为只读集合抛出。一个好的实现会在函数开始时立即执行此测试。

需要注意的一件重要事情是,类型在 C# 中不像在定义 LSP 的类型理论中那样受到限制。例如,您可以在 C# 中编写如下函数:

bool IsFrob(object bobicator)
{
return ((Bob)bobicator).IsFrob;
}

可以bobicator替换为 object 的任何父类(super class)型?显然不是。但这显然不是穷人的问题Frobinate类型 - 这是 IsFrob 中的一个错误功能。实际上,C#(以及大多数其他语言)中的许多代码仅适用于比方法签名中的类型所指示的对象更受限制的对象。

如果对象违反其父类(super class)型的约定,则该对象仅违反 LSP。它不能对 其他 代码违规 LSP 负责。通常你会发现编写不能完美在 LSP 下的代码是非常务实的——工程是,而且一直是,关于权衡。仔细权衡成本。

关于c# - Liskov 替换原则和接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44049593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com