如何将项添加到IEnumerable <t>集合?</t>

时间:2009-07-31 01:52:35

标签: c# list ienumerable

我的问题如上所述。例如,

IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));

但毕竟它里面只有1个项目。

我们可以使用像items.Add(item)这样的方法吗?

List<T>

类似

16 个答案:

答案 0 :(得分:429)

您不能,因为IEnumerable<T>不一定代表可以添加项目的集合。事实上,它并不一定代表一个集合!例如:

IEnumerable<string> ReadLines()
{
     string s;
     do
     {
          s = Console.ReadLine();
          yield return s;
     } while (s != "");
}

IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??

然而,你可以做的是创建一个新的 IEnumerable对象(未指定类型),当枚举时,它将提供旧项目的所有项目,以及一些你自己。您可以使用Enumerable.Concat

 items = items.Concat(new[] { "foo" });

不会更改数组对象(无论如何都不能将项目插入数组)。但它会创建一个新对象,列出数组中的所有项目,然后“Foo”。此外,该新对象将跟踪数组中的更改(即每当您枚举它时,您将看到项目的当前值)。

答案 1 :(得分:84)

类型IEnumerable<T>不支持此类操作。 IEnumerable<T>接口的目的是允许使用者查看集合的内容。不要修改值。

当您执行.ToList()。Add()等操作时,您正在创建新的List<T>并向该列表添加值。它与原始列表没有关联。

您可以使用添加扩展程序方法创建具有附加值的新IEnumerable<T>

items = items.Add("msg2");

即使在这种情况下,它也不会修改原始的IEnumerable<T>对象。这可以通过保持对它的引用来验证。例如

var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");

在这组操作之后,变量temp仍将仅在值集合中引用具有单个元素“foo”的枚举,而项目将引用具有值“foo”和“bar”的不同可枚举。

修改

我不断忘记Add不是IEnumerable<T>上的典型扩展方法,因为它是我最终定义的第一个扩展方法之一。这是

public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
  foreach ( var cur in e) {
    yield return cur;
  }
  yield return value;
}

答案 2 :(得分:48)

您是否考虑使用ICollection<T> IList<T>接口,它们的存在是因为您希望在IEnumerable&lt; T&gt;上使用“添加”方法。 IEnumerable的&LT; T&GT;用于将类型“标记”为......井......可枚举或仅仅是一系列项目,而不必保证真实底层对象是否支持添加/删除项目。还要记住,这些接口实现了IEnumerable&lt; T&gt;。因此,您将获得IEnumerable&lt; T&gt;所获得的所有扩展方法。同样。

答案 3 :(得分:29)

IEnumerableIEnumerable<T>上的一些简短,甜蜜的扩展方法为我做了:

public static IEnumerable Append(this IEnumerable first, params object[] second)
{
    return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
    return first.Concat(second);
}   
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
    return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
    return second.Concat(first);
}

优雅(嗯,非通用版本除外)。太糟糕了,这些方法都不在BCL中。

答案 4 :(得分:17)

没有IEnumerable不支持向其添加项目。

你'替代'是:

var List = new List(items);
List.Add(otherItem);

答案 5 :(得分:11)

要添加您需要的第二条消息 -

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})

答案 6 :(得分:10)

在.net Core中,有一种方法Enumerable.Append就是这样做的。

该方法的源代码是available on GitHub. ....实现(比其他答案中的建议更复杂)值得一看:)。

答案 7 :(得分:8)

您不仅可以添加像您所说的项目,而且如果您将项目添加到List<T>(或几乎任何其他非只读集合),您有一个现有的枚举器,则枚举器是无效(从此开始抛出InvalidOperationException)。

如果要汇总某些类型的数据查询结果,可以使用Concat扩展方法:

编辑:我最初在示例中使用了Union扩展名,这实际上并不正确。我的应用程序广泛使用它来确保重叠查询不会重复结果。

IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);

答案 8 :(得分:4)

其他人已经给出了很好的解释,说明为什么你不能(也不应该!)能够将项目添加到IEnumerable。我只想补充一点,如果您希望继续编写代表集合的接口并想要一个add方法,那么您应该编码为ICollectionIList。作为一个额外的富矿,这些接口实现IEnumerable

答案 9 :(得分:4)

我只是来这里说,除了Enumerable.Concat扩展方法之外,.NET Core 1.1.1中似乎还有另一个名为Enumerable.Append的方法。后者允许您将单个项目连接到现有序列。所以Aamol的答案也可以写成

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));

请注意,此函数不会更改输入序列,只返回一个将给定序列和附加项放在一起的包装器。

答案 10 :(得分:1)

你可以这样做。

//Create IEnumerable    
IEnumerable<T> items = new T[]{new T("msg")};

//Convert to list.
List<T> list = items.ToList();

//Add new item to list.
list.add(new T("msg2"));

//Cast list to IEnumerable
items = (IEnumerable<T>)items;

答案 11 :(得分:1)

实现 IEnumerable 和 IEnumerator(从 IEnumerable 返回)的实例没有任何允许更改集合的 API,该接口提供只读 API。

实际更改集合的两种方法:

  1. 如果实例恰好是一些带有写 API 的集合(例如 List),您可以尝试转换为这种类型:

IList<string> list = enumerableInstance as IList<string>;

  1. 从 IEnumerable 创建一个列表(例如,通过 LINQ 扩展方法 toList()

var list = enumerableInstance.toList();

答案 12 :(得分:0)

最简单的方法就是

Data added in Inspectors.aspx

然后你可以将列表作为IEnumerable返回,因为它实现了IEnumerable接口

答案 13 :(得分:-1)

很抱歉,您的问题真的很老,但是由于它被列在第一批Google搜索结果中,因此我认为有些人一直在这里着陆。

在很多答案中,其中一些确实很有价值并且得到了很好的解释,我想补充一个不同的观点,因为对我而言,这个问题尚未得到很好的识别。

您要声明一个存储数据的变量,您需要它能够通过向其中添加项目来进行更改吗?因此,您不应使用将其声明为IEnumerable。

由@ NightOwl888提议

对于此示例,只需声明IList而不是IEnumerable:IList items = new T [] {new T(“ msg”)}; items.Add(new T(“ msg2”));

尝试绕过声明的接口限制仅表明您做出了错误的选择。 除此之外,应该考虑提议用于实现其他实现中已经存在的事物的所有方法。 用于添加项目的类和接口已经存在。为什么总是重建在其他地方已经做过的事情?

这种考虑是在接口内抽象变量功能的目标。

TL; DR:IMO这些是您所需的最干净的方法:

// 1st choice : Changing declaration
IList<T> variable = new T[] { };
variable.Add(new T());

// 2nd choice : Changing instantiation, letting the framework taking care of declaration
var variable = new List<T> { };
variable.Add(new T());

当您需要将变量用作IEnumerable时,便可以使用。当需要将其用作数组时,可以调用“ ToArray()”,它实际上应该总是那么简单。不需要扩展方法,仅在真正需要时才进行强制转换,可以在变量上使用LinQ,等等...

不要做奇怪和/或复杂的事情,因为您只是在声明/实例化时犯了一个错误。

答案 14 :(得分:-2)

下面的代码解决了我的问题。

material.MaterialCasualties = material.MaterialCasualties.Append(materialCasualties).ToList();

OR

customCustomer.CustomCustomerPayments = customCustomer.CustomCustomerPayments.Concat(customCustomerPayment).ToList();

答案 15 :(得分:-8)

当然,你可以(我将你的T-business留在一边):

public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
    List<string> list = items.ToList();
    string obj = "";
    list.Add(obj);

    return list.Select(i => i);
}