lds*_*now 382 c# ienumerable list
我的问题如上所述.例如,
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
Run Code Online (Sandbox Code Playgroud)
但毕竟它里面只有1个项目.
我们可以有一个方法items.Add(item)吗?
像 List<T>
Pav*_*aev 455
您不能,因为IEnumerable<T>它不一定代表可以添加项目的集合.事实上,它并不一定代表一个集合!例如:
IEnumerable<string> ReadLines()
{
string s;
do
{
s = Console.ReadLine();
yield return s;
} while (!string.IsNullOrEmpty(s));
}
IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??
Run Code Online (Sandbox Code Playgroud)
但是,你可以做的是创建一个新 IEnumerable对象(未指定类型),当枚举时,它将提供旧对象的所有项目,以及你自己的一些项目.你用Enumerable.Concat它:
items = items.Concat(new[] { "foo" });
Run Code Online (Sandbox Code Playgroud)
这不会更改数组对象(无论如何都不能将项插入到数组中).但它会创建一个新对象,列出数组中的所有项目,然后"Foo".此外,该新对象将跟踪数组中的更改(即,只要您枚举它,您将看到项的当前值).
Jar*_*Par 89
该类型IEnumerable<T>不支持此类操作.IEnumerable<T>界面的目的是允许使用者查看集合的内容.不要修改值.
当您执行.ToList().Add()等操作时,您将创建一个新的List<T>并向该列表添加值.它与原始列表没有任何关联.
您可以使用Add扩展方法创建IEnumerable<T>具有附加值的new .
items = items.Add("msg2");
Run Code Online (Sandbox Code Playgroud)
即使在这种情况下,它也不会修改原始IEnumerable<T>对象.这可以通过保持对它的引用来验证.例如
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
Run Code Online (Sandbox Code Playgroud)
在这组操作之后,变量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;
}
Run Code Online (Sandbox Code Playgroud)
Abh*_*tel 53
您是否考虑使用ICollection <T>或IList <T>接口,它们的存在是因为您希望在IEnumerable <T>上使用"添加"方法.IEnumerable <T>用于将类型"标记"为......井......可枚举或只是一系列项目,而不必保证真实底层对象是否支持添加/删除项目.还要记住,这些接口实现了IEnumerable <T>,因此您获得了使用IEnumerable <T>获得的所有扩展方法.
小智 31
一些简短,甜蜜的扩展方法,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);
}
Run Code Online (Sandbox Code Playgroud)
优雅(嗯,非通用版本除外).太糟糕了,这些方法都不在BCL中.
Pau*_*enk 19
没有IEnumerable不支持向其添加项目.
你'另类'是:
var List = new List(items);
List.Add(otherItem);
Run Code Online (Sandbox Code Playgroud)
Jan*_*Net 18
在.net Core中,有一种方法Enumerable.Append就是这样做的.
该方法的源代码可在GitHub上获得.....实施(比其他答案中的建议更复杂)值得一看:).
Aam*_*mol 14
要添加第二条消息,您需要 -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
Run Code Online (Sandbox Code Playgroud)
您不仅可以添加像您所述的项目,而且如果您将项目添加到List<T>(或几乎任何其他非读取集合)您拥有现有枚举器,则枚举器将失效(InvalidOperationException从此开始抛出).
如果要汇总某些类型的数据查询的结果,可以使用Concat扩展方法:
编辑:我最初Union在示例中使用了扩展名,这不是很正确.我的应用程序广泛使用它来确保重叠查询不会重复结果.
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
Run Code Online (Sandbox Code Playgroud)
我只是在这里说的是,除了Enumerable.Concat扩展方法外,Enumerable.Append.NET Core 1.1.1中似乎还有另一种方法。后者允许您将单个项目连接到现有序列。所以Aamol的答案也可以写成
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
Run Code Online (Sandbox Code Playgroud)
不过,请注意,此函数不会更改输入序列,它只是返回将给定序列和附加项放在一起的包装器。
其他人已经给出了关于为什么您不能(也不应该!)能够将项目添加到IEnumerable. 我只会补充一点,如果您希望继续对表示集合的接口进行编码并想要一个 add 方法,那么您应该对ICollectionor进行编码IList。作为额外的财富,这些接口实现了IEnumerable.