【问题标题】:Cannot add items to an IList/List being casted from an IEnumerable无法将项目添加到从 IEnumerable 投射的 IList/List
【发布时间】:2011-04-19 14:33:43
【问题描述】:

我正在尝试为我的老板创建一个小型的概念验证应用程序,但是我创建的模拟他尝试实现的代码不起作用。

for (int i = 0; i < 5000; i++)
{
     ((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
}

我试图在一行中完成所有这些,因为这就是他的代码前几天在我们正在开发的框架中的样子。当上面的代码执行时,我得到一个运行时错误,说“集合是固定大小的”。当我尝试转换为 List 而不是 IList 时,我收到一个 InvalidCastException,说“无法将 'System.String[]' 类型的对象转换为 'System.Collections.Generic.List`1[System.String]' 。”

任何人对我如何实现单行转换以将项目添加到 IEnumerable 或帮助我找出解决我不断遇到的两个错误的方法有任何想法?提前致谢。

编辑(美国东部标准时间 2011 年 4 月 19 日上午 10:49) 我正在添加更多代码来帮助人们 - 可能应该早点这样做。对不起。

程序.cs:

        #region Cast Test
        Class1 obj2 = new Class1();
        obj2.Stuff = Enumerable.Empty<string>();

        Console.WriteLine("Cast - Start Time: " + 0 + "ms");

        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch.Start();

        for (int i = 0; i < 5000; i++)
        {
            ((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
        }

        stopwatch2.Stop();
        Console.WriteLine("Cast - Stop Time: " + stopwatch2.ElapsedMilliseconds.ToString() + "ms");
        #endregion

Class1.cs:

public class Class1
{
    private IEnumerable<string> stuff;

    public IEnumerable<string> Stuff
    {
        get { return stuff; }
        set { stuff = value; }
    }
}

【问题讨论】:

  • obj2.Stuff 的 REAL 类型是什么?从异常来看,它看起来像一个字符串[]?
  • 请张贴定义obj2.Stuff的代码。我的直觉是 obj2.Stuff 是一个数组而不是 List 类型。
  • @Daniel & Muad'Dib:obj2 只是一个对象。 Stuff 只是所述对象的 IEnumerable 属性。
  • IEnumerable&lt;string&gt; 没有 Add 方法。将其转换为不同的类型不会神奇地创建新属性,如果它们已经存在,它只会公开它们。
  • 你要打到IEumerable吗?

标签: c# list casting ienumerable


【解决方案1】:

C# 中的数组是固定大小的。您无法向其中添加项目。

【讨论】:

    【解决方案2】:

    您不能将string[] 强制转换为IList&lt;string&gt;,因为string[] 没有实现该接口。您需要先创建一个实现IList&lt;string&gt; 的对象:

    List<string> list = obj2.Stuff.ToList();
    for (int i = 0; i < 5000; i++)
    {
         list.Add("Iteration " + i.ToString());
    }
    

    【讨论】:

    • 我们试图避免将 IEnumerable 复制到列表中(因为在框架中我们必须将列表分配回 IEnumerable;我们试图找出哪个会更多高效:复制或转换)。谢谢(和+1)关于我的 IList/string[] 错误的技术解释——在我在这里开始我的新工作之前的过去六个月里,我一直在处理垃圾 VBScript,所以我有点在 C# 上生锈。
    • 其实你可以将string[]转换成IList&lt;string&gt;,但是IsFixedSize会是真的,当你调用Add时会导致异常。
    • @juharr:是的——肯定遇到了这个问题。 :(
    【解决方案3】:

    为什么要在 for 循环中强制转换?虽然每个 IList 都是 IEnumerable,但并非每个 IEnumerable 都是 IList。您可以使用 ToList 扩展方法将 IEnumerable 复制到新列表。 (一定要using System.Linq;

    另外,在本例中,不需要 for 循环:

    var list = obj2.Stuff.ToList();
    new list.AddRange(Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString()));
    

    【讨论】:

    • +1 用于单行替换循环(它为我提供了一个有用的 Lambda 示例 [我不完全理解])。不幸的是,我无法使用此解决方案,因为我特别想避免将我的对象复制到列表中。
    【解决方案4】:

    在上面某个答案的 cmets 中,您说“我试图避免复制列表。”

    您正在尝试将数据添加到基础类型为IEnumerable&lt;T&gt; 的对象。但是IEnumerable 对象并不是一个真正的容器,它是一个接口。您不能向界面添加内容。但是您可以将实现该接口的另一个对象分配给它。

    所以要使用上面foson的例子,你可以这样做:

    obj2.Stuff = Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString());
    

    请注意,当此代码执行时,实际上并没有发生任何事情。在实际迭代 obj2.Stuff 之前,不会创建任何对象。发生这种情况时,将调用 LINQ 中的方法,一次创建一个对象并将它们返回到迭代器循环。

    但这里不涉及实际的存储设备。您可以迭代 obj2.Stuff,除非您随后将每个整数添加到其他内容中,否则它们将在下一次迭代中消失。

    这里的基本点是你不能在IEnumerable 中存储东西,相反,IEnumerable 是一种按顺序返回对象的方法,它可以来自列表构造,也可以来自生成序列的函数.

    【讨论】:

    • 实际上那行代码确实创建了一个对象。实现 'IEnumerable' 的对象。您真正的意思是没有创建枚举中的任何对象。
    • 是的,这就是我的意思,枚举中的对象。
    【解决方案5】:

    您不能调用Add,因为obj2.Stuff 似乎是一个数组,并且数组具有固定大小,如错误消息所示。

    【讨论】:

      【解决方案6】:

      System.String[] 类型是一个字符串数组,它实现了IEnumerable&lt;string&gt;,但不是List&lt;string&gt;。数组是固定长度的。为什么需要一行?

      【讨论】:

      • 我想它可能是两个或更多,只要我能够成功完成我的演员表(而不是复制对象)。
      【解决方案7】:

      将 obj2.Stuff 的类型更改为 StringCollection 或 List 之类的类型。在 .NET 中,数组是固定长度的,您不能向其中添加新对象,因此请改用集合。

      【讨论】:

        【解决方案8】:

        IEnumerable 不会为您提供与IList 相同的功能。除非您的 StuffIEnumerable 也是 IList,否则您的代码将无法正常工作。

        第一个合约只承诺您可以一次迭代一个元素。它从不声明您可以添加新元素。

        只有当且仅当您的可枚举对象在运行时也满足IList 接口时,您才能取消此操作。

        【讨论】:

          【解决方案9】:

          由于obj2.Stuff 是一个字符串数组,因此无法执行您想要执行的操作。数组无法调整大小,因此您无法向其中添加项目。

          如果您可以将obj2.Stuff 中的数组替换为另一个数组,您可以从数组中获取数据并从中创建一个列表,将项目添加到列表中,从列表中获取数据并从中创建一个数组,并用它来替换原来的数组:

          List<string> items = new List<string>(obj2.Stuff);
          for (int i = 0; i < 5000; i++) {
            items.Add("Iteration " + i.ToString());
          }
          obj2.Stuff = items.ToArray();
          

          如果obj2.Stuff 属性是只读的,那么您不能向其中添加任何内容,除非您将底层实现从数组更改为可以添加项目的集合。

          【讨论】:

          • obj2.Stuff 是一个 IEnumerable。确实不能调整大小,但您可以将其转换为 IList(或使用 Add() 方法的其他东西),这将允许您调整它的大小。
          • @KSwift87:是的,它是IEnumerable&lt;string&gt;,但您的错误消息显示它的实际类型是string[]。尽管您可以将其转换为IList&lt;string&gt;,但它仍然是一个数组,并且无法调整大小。由于数组实现了IList&lt;T&gt; 接口,它们有一个Add 方法,但是你不能使用它来向数组中添加项目,因为它所做的只是抛出一个NotSupportedException
          猜你喜欢
          • 2013-07-29
          • 2011-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          相关资源
          最近更新 更多