如何将项目添加到IEnumerable <T>集合?
我的问题如上所述。 例如,
IEnumerable<T> items = new T[]{new T("msg")}; items.ToList().Add(new T("msg2"));
但毕竟它里面只有一件东西。
我们可以有一个方法像items.Add(item)
?
像List<T>
您不能,因为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??
但是,您可以做的是创build一个新的 IEnumerable
对象(未指定types),枚举时将提供所有旧项目以及您自己的项目。 您使用Enumerable.Concat
为:
items = items.Concat(new[] { "foo" });
这不会改变数组对象 (无论如何你都不能将项目插入到数组中)。 但它会创build一个新的对象,列出数组中的所有项目,然后是“Foo”。 而且,这个新的对象将跟踪数组中的变化 (例如,每当你枚举它,你会看到项目的当前值)。
IEnumerable<T>
types不支持这种操作。 IEnumerable<T>
接口的目的是让消费者查看集合的内容。 不要修改这些值。
当您执行像.ToList()。Add()这样的操作时,您正在创build一个新的List<T>
并将值添加到该列表中。 它与原始列表没有关系。
您可以使用Add扩展方法创build一个新的具有附加值的IEnumerable<T>
。
items = items.Add("msg2");
即使在这种情况下,它也不会修改原始的IEnumerable<T>
对象。 这可以通过参考来validation。 例如
var items = new string[]{"foo"}; var temp = items; items = items.Add("bar");
在这组操作之后,variablestemp将仍然只引用具有值集合中的单个元素“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; }
你有没有考虑使用ICollection <T>或IList <T>接口,它们存在的原因是你想在IEnumerable <T>上有一个'Add'方法。 IEnumerable <T>用于将types标记为…以及可枚举或只是一系列的项目,而不必确保真实的底层对象是否支持添加/删除项目。 还要记住,这些接口实现IEnumerable <T>,所以你可以获得IEnumerable <T>获得的所有扩展方法。
对于IEnumerable
和IEnumerable<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中。
IEnumerable不支持添加项目。
一个'替代'你有。
var List = new List(items); List.Add(otherItem);
你不仅可以添加像你陈述的项目,但是如果你添加一个项目到一个List<T>
(或几乎任何其他非只读集合),你有一个现有的枚举器,枚举器是无效的(抛出InvalidOperationException
从那时起)。
如果您正在汇总某种types的数据查询的结果,则可以使用Concat
扩展方法:
编辑:我原来在例子中使用了Union
扩展,这是不正确的。 我的应用程序广泛使用它来确保重叠查询不会重复结果。
IEnumerable<T> itemsA = ...; IEnumerable<T> itemsB = ...; IEnumerable<T> itemsC = ...; return itemsA.Concat(itemsB).Concat(itemsC);
要添加第二条消息,你需要 –
IEnumerable<T> items = new T[]{new T("msg")}; items = items.Concat(new[] {new T("msg2")})
其他人已经给出了很好的解释,为什么你不能(不应该)能够添加项目到IEnumerable
。 我只会补充一点,如果你想继续编码到代表一个集合的接口,并且想要一个add方法,你应该编码到ICollection
或者IList
。 作为一个附加的富矿,这些接口实现IEnumerable
。
你可以这样做。
//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;
我只是来这里说,除了Enumerable.Concat
扩展方法外,在.NET Core 1.1.1中似乎还有一个名为Enumerable.Append
方法。 后者允许您将单个项目连接到现有序列。 所以阿莫尔的回答也可以写成
IEnumerable<T> items = new T[]{new T("msg")}; items = items.Append(new T("msg2"));
不过,请注意,这个函数不会改变input序列,它只是返回一个包装,将给定的序列和附加的项目放在一起。
在.net核心中,有一个方法Enumerable.Append
正是那样做的。
该方法的源代码在GitHub上可用。 ….实现(比其他答案中的build议更复杂)值得一看:)。
最简单的方法是简单的
IEnumerable<T> items = new T[]{new T("msg")}; List<string> itemsList = new List<string>(); itemsList.AddRange(items.Select(y => y.ToString())); itemsList.Add("msg2");
那么你可以返回列表IEnumerable也因为它实现IEnumerable接口
当然,你可以(我将你的电子商务放在一边):
public IEnumerable<string> tryAdd(IEnumerable<string> items) { List<string> list = items.ToList(); string obj = ""; list.Add(obj); return list.Select(i => i); }