我有一个List<>我的对象,但现在需要将其更改为IEnumerable<>。所以,我有这个:
public IEnumerable<TransactionSplitLine> TransactionSplitLines { get; set; }
然而,我再也不能这样做了:
reply.TransactionSplitLines.Add(new TransactionSplitLine
{Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)});
我现在应该如何添加项目?
答案 0 :(得分:19)
您可以使用Concat执行以下操作:
reply.TransactionSplitLines =
reply.TransactionSplitLines.Concat(new []{new TransactionSplitLine {
Amount = "100",
Category = "Test",
SubCategory = "Test More",
CategoryId = int.Parse(c)}});
这基本上会创建一个新的IEnumerable
。在您的案例中很难说出最佳解决方案是什么,因为没有足够的有关您的用例的信息。
修改强>
请注意List<T>
实施IEnumerable<T>
。因此,如果您需要传递IEnumerable<T>
作为参数,您也可以传递List<T>
,也可以先在列表中明确调用AsEnumerable()
。所以也许你可以坚持使用List而不是IEnumerable。
答案 1 :(得分:9)
简答:您无法将项目添加到IEnumerable<T>
稍微长一点的解释:
IEnumerable
是一个仅关注能够枚举/迭代项集合的接口。这是IEnumerable
存在的唯一目的。它抽象出了存储或检索可枚举项的方式的任何概念(它可能是字符串,项列表,字节流或计算结果系列),因此如果您的接口是{ {1}},您无法向其中添加项目,只能对其提供的项目进行迭代。
也就是说,将项目添加到IEnumerable
的正确方式是返回新的IEnumerable
,并将新项目附加到原始内容中。
对于Linq库,您还有一个扩展方法,允许通过IEnumerable
将您的IEnumerable转换为List,并且您可以将项添加到列表中。但这不是正确的方式。
使用命名空间中的Linq库,您可以执行以下操作:
IEnumerable.ToList()
答案 2 :(得分:5)
您无法将项目添加到IEnumerable<T>
,因为此界面没有Add
方法
如果TransactionSplitLines
始终返回List<TransactionSplitLine>
的实例,您可能希望将其类型更改为IList<TransactionSplitLine>
。
如果您无法更改TransactionSplitLines
的类型,并且可以保证始终返回IList<TransactionSplitLines>
,则可以将其转换为
((IList<TransactionSplitLine>)reply.TransactionSplitLines).Add(new TransactionSplitLine
{Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)});
答案 3 :(得分:3)
IEnumerable<T>
没有Add(T)
方法。根据您的真实类型,您可以像这样投射:
var item = new TransactionSplitLine {Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)};
((IList)reply.TransactionSplitLines).Add(item);
如果您正在使用的集合实现IList
。
请记住,当您传递对象时,您希望使用最基本的接口/类。因此,如果您需要使用IList
中的方法,我建议您使用该方法而不是IEnumerable
。
我建议你做以下更改:
public IList<TransactionSplitLine> TransactionSplitLines { get; set; }
答案 4 :(得分:2)
这取决于TransactionSplitLines
属性的含义和目的。
如果您想允许从课堂外进行编辑(添加/删除),那么只需使您的属性不如IEnumerable<T>
那样通用:
public IList<TransactionSplitLine> TransactionSplitLines { get; set; }
或更好:
public ICollection<TransactionSplitLine> TransactionSplitLines { get; set; }
相反,如果你只需要在内部编辑集合(我的意思是在类范围内),你为什么不这样做:
private List<TransactionSplitLine> transactionSplitLines;
public IEnumerable<TransactionSplitLine> TransactionSplitLines
{
get
{
return transactionSplitLines;
}
}
因此您可以使用transactionSplitLines
字段在内部更改集合。
答案 5 :(得分:2)
我会创建这个扩展方法,它可以完成所有这些工作:
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] items)
{
return source.Concat(items);
}
所以在你的情况下:
var item = new TransactionSplitLine { Amount = "100", Category = "Test",
SubCategory = "Test More",
CategoryId = int.Parse(c) };
reply.TransactionSplitLines.Append(item);
您可以同样拥有Prepend
:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] items)
{
return items.Concat(source);
}
答案 6 :(得分:0)
您可以使用Concat
方法连接两个集合:
reply.TransactionSplitlines = reply.TransactionSplitlines.Concat(/* another enumerable */);
您需要编写一个扩展方法AsEnumerable
,该方法需要obj
并执行yield return obj;
之类的操作。您可以避免编写扩展方法,只需将带有对象的new []
传递给Concat
方法,但如果您的界面基于IEnumerable
,则可能需要在其他一些情况下也是AsEnumerable
方法。
如果你确实需要它IEnumerable
那就是。但是,我建议考虑切换到IList<T>
或其他支持add
的界面。如果你需要通过IEnumerable<>
属性来实现某个接口,你可以将IList<>
作为此属性的内部字段并单独修改它 - 可能性是你在这里使用具体对象,不是界面。如果您正在使用该界面并仍需要使用Add
,IEnumerable<>
只是此界面类型的错误选择。
答案 7 :(得分:0)
IEnumerable是不可变的集合,它意味着你无法添加或删除项目。 Extension方法创建一个新实例。(例如:What's the Best Way to Add One Item to an IEnumerable<T>?解释) 相反,然后创建扩展方法,最初可以添加到列表,如下所示: 例如,在我的情况下,用户角色被定义为IEnumerable(在用户模型类中)。所以,为了增加该角色的价值。最初我定义了一个列表:
List<Role> rols=new List<Role>();
内部for循环为此列表增加了值,如:
foreach(int i=0;i<chkRoles.count;i++)
{
Role r=new Role();
r.RoleId="2";
r.RoleName="Admin";
rols.add(r);
}
然后将此值提供给IEnumerable ist:
user.Roles=rols.AsEnumerable();