为什么string不实现IList <char>?

ord*_*dag 5 .net c# string

标题说全部

为什么要String实施IEnumerable<char>而不是IList<char>

字符串具有长度,您可以从特定索引中获取元素.
并且可以表明它是不可改变的ICollection<char>.IsReadOnly.

那么它可能有什么问题呢?我错过了什么吗?

正如许多答案所指出的那样: 没有单独的只读列表/集合的界面,但是作为ReadOnlyCollection<T>节目,我认为它绝对可能并且使用它IsReadOnly为这种情况设计的属性.

   public class String : IList<char>
    {
        int IList<char>.IndexOf(char item)
        {
            // ...
        }

        void IList<char>.Insert(int index, char item)
        {
            throw new NotSupportedException();
        }

        void IList<char>.RemoveAt(int index)
        {
            throw new NotSupportedException();
        }

        char IList<char>.this[int index]
        {
            set
            {
                throw new NotSupportedException();
            }
        }

        void ICollection<char>.Add(char item)
        {
            throw new NotSupportedException();
        }

        void ICollection<char>.Clear()
        {
            throw new NotSupportedException();
        }

        public bool Contains(char item)
        {
            // ...
        }

        public void CopyTo(char[] array, int arrayIndex)
        {
            // ...
        }

        int ICollection<char>.Count
        {
            get { return this.Length; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        bool ICollection<char>.Remove(char item)
        {
            throw new NotSupportedException();
        }

        // ...
    }
Run Code Online (Sandbox Code Playgroud)

Jef*_*nal 14

主要是因为IList继承自ICollection,而字符串不支持可变的beahviors ICollectionpromises(添加,删除和清除) - 当您从字符串添加或删除字符元素时,它会创建一个新字符串.


实现接口的一部分是糟糕的设计.你有时可能会出于必要而做,但这绝不是一个好的选择.分割界面更好.(可能已经拆分了.NET集合接口以将可变成员与诊断成员隔离开来.)元函数IsReadOnly使得界面不那么连贯并使其更难使用.

所以即使一个字符串在很多方面都是一个列表 - 你可以索引一个字符串并找到其中的字符数 - 很少有人真正想要像对待一个字符串IList<char>,特别是在3.5后的世界中当有简单的转换时,可以很容易地从中获取此信息IEnumerable<char>.


Tim*_*oyd 5

我认为高度ReadOnlyCollection支持的事实是: mehIList

IList是一个契约,表明实现者支持集合突变(例如添加、删除、插入),这在不可变对象上显然是错误的。将其转移到System.String是完全错误的,因为它在设计上也是不可变的。

System.String实现IList将是一个糟糕的 API 设计,因为一堆方法将不起作用,因此字符串不会以与完全实现的类型相同的方式工作IList

也许您希望它支持更自由的界面,当然,但这IList不是正确的选择。

像这样的部分接口实现打破了里氏替换原则,并引入了潜在的运行时错误。

更新

有趣的是,.Net 4.5 引入了新的IReadOnlyList接口。但是,String没有实现它,并且无法将其引入IList层次结构中。

一些背景:http://www.infoq.com/news/2011/10/ReadOnly-WInRT

  • @ordag 这将是错误的设计,因为它破坏了 LSP。你真正想要的是字符串实现一个更方便的接口,我同意这一点,但是,这个接口不存在。 (2认同)
  • 是的,我可以将我的论点转移到数组 - 正确。该框架并不完美。这就是为什么我暗示我们希望有不存在的接口。 (2认同)

seh*_*ehe 1

主要是,它不是一个 IList(你不能"hello world".Add('!')——这是一个接口和契约不兼容;它不仅仅是一个只读列表,因为它会“知道”该Add操作,并在调用时抛出)。


此外,字符串具有特殊的语义 - 存储优化和身份别名(可以有小字符串优化,可以有内部字符串)。一旦您传递为,这些就不会脱颖而出IList<char>- 人们可能会开始期待“正常”的类似 List<> 的语义。

然而,当看到 时IEnumerable<char>,并没有提出这样的期望(它只是说:我可以连续给你一些角色,你不需要知道他们来自哪里)。