【问题标题】:Why does calling Add throw an exception in a collection cast to ICollection<T>?为什么调用 Add 会在 ICollection<T> 的集合中抛出异常?
【发布时间】:2018-02-13 17:25:01
【问题描述】:

我不太确定我是否理解什么 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&lt;string&gt;(顺便说一下,它与 IReadableCollection&lt;string&gt; 不同)之后,我本来希望添加一个新元素来工作。

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

我从这里发现 数组类显式实现了IList.Add(Object) 并且调用此方法总是会引发 NotSupportedException 异常。

这就是为什么第一次调用会抛出错误的解释吗?

如果是这样,是否可以假定AddArray 类中的一个方法,它覆盖了IList 中的Add 方法? (覆盖关键字而不是新关键字) 例如如果它是一个新方法而不是覆盖,那行就不会抛出错误,是吗?

其次,这种情况的原因是:在预期是通常可修改的集合ICollection&lt;T&gt;(而不是IReadableCollection&lt;T&gt;)中,我们有一个名为IsReadOnly的属性?

感谢您的澄清。

【问题讨论】:

  • 你怎么能期望它起作用?它会做什么?铸造不会改变任何东西。它仍然是一个数组;你只是看待它的方式不同。
  • 同意 SLaks。我认为您混淆了 Conversion 和 Cast,而 Conversion 通常从一种类型复制到另一种类型。
  • 您将转换和转换混为一谈,这无疑是由于某些转换也执行转换的事实。很不幸。但简单的事实是这里没有发生转换,这就是 Add 失败的原因。
  • Anthony Pegram,很有趣,有些演员也执行转换?你能详细说明一下吗?谢谢大家!
  • @hhdr103 从一个类到另一个类的自定义转换使用熟悉的“(Cast)”语法。原语的转换也是如此 (int x = (int)some decimal;)。当然,这些是例外,而不是规则。

标签: c# arrays


【解决方案1】:

铸造某物并不会神奇地将其更改为拥有该某物的所有方法。数组仍然是数组;强制转换通常用于您想阅读某些内容而不是修改它。无论如何,从可维护性/易读性的角度来看,这都是不可取的。如果您想要一个可变集合,这可能是您正在寻找的:

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

【讨论】:

    【解决方案2】:

    是的,NotSupportedException 可能是您通过调用从数组转换的 ICollection 中的 Add 方法获得的异常。

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

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

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

    IList 接口相当陈旧,我不确定在其中添加此属性的目的是什么。如果您打算让一个实现 IList 的类无法更改,我建议您反对它。有一个概念叫做接口隔离原则(SOLID 中的 I),所以如果你需要实现一个只读的集合,你最好实现一个没有添加新项的方法的接口。 这个IsReadOnly 的一个很好的用法是在IList 的实现中指示一个状态,因此基于某些东西,例如列表中的项目数量,您可以指示您的列表处于只读状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 2013-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多