为什么通用的ICollection在.NET 4.5中没有实现IReadOnlyCollection?[英] Why doesn't generic ICollection implement IReadOnlyCollection in .NET 4.5?

本文是小编为大家收集整理的关于为什么通用的ICollection在.NET 4.5中没有实现IReadOnlyCollection?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

in .net 4.5/c#5,IReadOnlyCollection<T>用Count属性声明:

public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }
}

我想知道,ICollection<T>也实现IReadOnlyCollection<T>接口是否有意义:

public interface ICollection<T> : IEnumerable<T>, IEnumerable, *IReadOnlyCollection<T>*

这将意味着实现ICollection<T>的类将自动实施IReadOnlyCollection<T>.这对我来说很合理.

ICollection<T>抽象可以看作是IReadOnlyCollection<T>抽象的扩展.请注意,例如,List<T>同时实现了ICollection<T>和IReadOnlyCollection<T>.

但是,它没有以这种方式设计.

我在这里想念什么?为什么选择当前的实现?


更新

我正在寻找一个使用面向对象的设计推理的答案解释原因:

  • 一个具体类,例如List<T>同时实现IReadOnlyCollection<T> 和 ICollection<T>

是一个更好的设计,比:

  • ICollection<T>实施IReadOnlyCollection<T>直接

另外,请注意,这与:

实质上是相同的问题
  1. 为什么不实施IReadOnlyList<T>?
  2. 为什么不实施IDictionary<T>?

推荐答案

乔恩就在这里 https://stackoverflow.com/a/12622784/395144 将他的答复标记为答案:

int ICollection<Foo>.Count { ... } // compiler error!

由于接口可以具有明确的实现,因此提取基本接口不向后兼容(在基础类中,您没有这个问题).

这就是为什么...

Collection<T> : IReadOnlyCollection<T>
List<T> : IReadOnlyList<T>
Dictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>

...但不是它们的接口.

imho,他们最初犯了一个设计错误,现在完全无法解决(不破坏事物).

编辑:隐藏无济于事,旧的(显式)实现仍然无法构建(不修改代码):

interface INew<out T> { T Get(); }

interface IOld<T> : INew<T>
{
    void Set(T value);
    new T Get();
}

class Old<T> : IOld<T>
{
    T IOld<T>.Get() { return default(T); }
    void IOld<T>.Set(T value) { }
}

'sample.old'不实现接口成员'sample.inew.get()'

其他推荐答案

可能有几个原因.这是一些:

  • 巨大的向后兼容性问题

    您将如何编写ICollection<T>的定义?这看起来很自然:

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        int Count { get; }
    }
    

    但是它有问题,因为IReadOnlyCollection<T>也声明了Count属性(编译器将在此处发出警告).除了警告外,将其视为(等同于编写new int Count)允许实施者通过至少明确实现两个Count属性具有不同的实现.如果两个实现决定返回不同的值,这可能是"有趣的".允许人们射击脚不是C#的风格.

    好吧,那:

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        // Count is "inherited" from IReadOnlyCollection<T>
    }
    

    好吧,这打破了决定明确实现的所有现有代码:

    class UnluckyClass : ICollection<Foo>
    {
         int ICollection<Foo>.Count { ... } // compiler error!
    }
    

    因此,在我看来,对这个问题没有好的解决方案:要么打破现有代码,要么强迫 emherephere 上强制实现.因此, .

其他推荐答案

这将是语义上的错误,因为显然,并非每个ICollection都是只读的.

也就是说,他们本可以称为接口IReadableCollection,而实现可以称为ReadOnlyCollection.

但是,他们没有走那条路.为什么?我看到 BCL团队成员写道,他们不希望收藏API变得太复杂的. (坦率地说)

本文地址:https://www.itbaoku.cn/post/627636.html

问题描述

In .NET 4.5 / C# 5, IReadOnlyCollection<T> is declared with a Count property:

public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
{
    int Count { get; }
}

I am wondering, wouldn't it have made sense for ICollection<T> to implement the IReadOnlyCollection<T> interface as well:

public interface ICollection<T> : IEnumerable<T>, IEnumerable, *IReadOnlyCollection<T>*

This would've meant that classes implementing ICollection<T> would've automatically implemented IReadOnlyCollection<T>. This sounds reasonable to me.

The ICollection<T> abstraction can be viewed as an extension of the IReadOnlyCollection<T> abstraction. Note that List<T>, for example, implements both ICollection<T> and IReadOnlyCollection<T>.

However it has not been designed that way.

What am I missing here? Why would the current implementation have been chosen instead?


UPDATE

I'm looking for an answer that uses Object Oriented design reasoning to explain why:

  • A concrete class such as List<T> implementing both IReadOnlyCollection<T> and ICollection<T>

is a better design than:

  • ICollection<T> implementing IReadOnlyCollection<T> directly

Also please note that this is essentially the same question as:

  1. Why doesn't IList<T> implement IReadOnlyList<T>?
  2. Why doesn't IDictionary<T> implement IReadOnlyDictionary<T>?

推荐答案

Jon was right here https://stackoverflow.com/a/12622784/395144 , you should mark his reply as the answer:

int ICollection<Foo>.Count { ... } // compiler error!

Since interfaces can have explicit implementations, extracting base interfaces is not backward compatible (with base classes you don't have this problem).

That's why...

Collection<T> : IReadOnlyCollection<T>
List<T> : IReadOnlyList<T>
Dictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>

... but not their interfaces.

IMHO, they did a design error initially, quite unresolvable now (without breaking things).

EDIT: hiding doesn't help, old (explicit) implementations won't still build (without modifying the code):

interface INew<out T> { T Get(); }

interface IOld<T> : INew<T>
{
    void Set(T value);
    new T Get();
}

class Old<T> : IOld<T>
{
    T IOld<T>.Get() { return default(T); }
    void IOld<T>.Set(T value) { }
}

'Sample.Old' does not implement interface member 'Sample.INew.Get()'

其他推荐答案

There are probably several reasons. Here are some:

  • Huge backwards compatibility problems

    How would you write the definition of ICollection<T>? This looks natural:

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        int Count { get; }
    }
    

    But it has a problem, because IReadOnlyCollection<T> also declares a Count property (the compiler will issue a warning here). Apart from the warning, leaving it as-is (which is equivalent to writing new int Count) allows implementors to have different implementations for the two Count properties by implementing at least one explicitly. This might be "amusing" if the two implementations decided to return different values. Allowing people to shoot themselves in the foot is rather not C#'s style.

    OK, so what about:

    interface ICollection<T> : IReadOnlyCollection<T>
    {
        // Count is "inherited" from IReadOnlyCollection<T>
    }
    

    Well, this breaks all existing code that decided to implement Count explicitly:

    class UnluckyClass : ICollection<Foo>
    {
         int ICollection<Foo>.Count { ... } // compiler error!
    }
    

    Therefore it seems to me that there's no good solution to this problem: either you break existing code, or you force an error-prone implementation on everyone. So the only winning move is not to play.

其他推荐答案

It would be semantically wrong, because obviously, not every ICollection is read-only.

That said, they could have called the interface IReadableCollection, while an implementation could be called ReadOnlyCollection.

However, they didn't go that route. Why? I saw a BCL team member write that they didn't want the collections API to become too convoluted. (Although it already is, frankly.)