为什么调用Add会在转换为ICollection <t>的集合中抛出异常?

时间:2018-02-13 17:25:02

标签: c# arrays

我不太清楚我是否理解OOP原则阻止我使用类型B中的方法来构建类型A。

具体示例:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        string[] week = new string[] { "Monday", "Tuesday", "wednesday", "Saturday", "Sunday"};
        ICollection<string> coll = (ICollection<string>)week;
        coll.Add("SlaveDay"); // this throws an error

        ICollection<string> coll2 = new List<string>() { "Monday", "Tuesday", "wednesday", "Saturday", "Sunday" };
        coll2.Add("SlaveDay"); // this works

    }
}

当然,数组是固定大小的,所以我理解为什么周(类型为string[]或字符串数​​组)不能添加任何新元素。 但是,在我明确地将它转换为ICollection<string>(顺便说一下,与IReadableCollection<string>不同)之后,我原本期望添加一个新元素。

https://msdn.microsoft.com/en-us/library/system.array.aspx#Remarks

我从这里发现了 数组类显式实现IList.Add(Object)调用此方法始终抛出NotSupportedException异常。

这是第一次调用抛出错误原因的解释吗?

如果是这样,是否可以假设AddArray类中的一种方法,它覆盖了来自Add的{​​{1}}方法? (覆盖关键字而不是新的) 例如如果它是一种新方法而不是覆盖,那条线就不会抛出错误,是吗?

其次,这种情况的原因是:在预期通常可修改的集合IList(与ICollection<T>相对)中,我们有一个名为IReadableCollection<T>的属性?

感谢您的澄清。

2 个答案:

答案 0 :(得分:1)

投射某些东西并没有神奇地改变它以拥有该东西的所有方法。数组仍然是一个数组;当你想要阅读某些内容而不是修改它时,通常会进行转换。无论如何,从可维护性/易读性的角度来看,它是不合需要的。如果你想要一个可变的集合,这就是你可能正在寻找的东西:

    string[] week = new string[] { "Monday", "Tuesday", "wednesday", "Saturday", "Sunday"};
    var coll = week.ToList();
    coll.Add("SlaveDay");

答案 1 :(得分:0)

是的,NotSupportedException可能是你通过调用从数组中铸造的ICollection中的Add方法获得的异常。

  

可以假设Add是Array类中的一个方法,它覆盖了IList的Add方法吗?

数组类没有“覆盖”来自IList的Add,因为IList是一个接口,而Array是一个类。类实现接口只是为了“遵守”接口的契约。 在C#中(不确定其他语言)可以explicitly implement接口方法。通过这样做,只有在保存带有接口类型的变量时才能使用实现的方法,这就是为什么在将数组转换为ICollection时只能看到“Add”方法的原因。 数组类可能有一行实现,用于抛出NotSupportException

的Add方法
  

是这种情况的原因:在预期通常可修改的集合ICollection(与IReadableCollection相对)中,我们有一个名为IsReadOnly的属性?

IList界面已经很老了,我不确定在那里添加这个属性的目的是什么。如果你打算有一个实现IList的类无法更改,我会建议反对它。有一个名为接口隔离原则(我在SOLID中)的概念,因此如果您需要实现一个只读的集合,理想情况下应该实现一个没有添加新项的方法的接口。 这个IsReadOnly的一个很好的用法是在IList的实现中指明一个状态,因此根据某些内容(例如列表中的项目数量),您可以指示您的列表处于读取状态只有国家。