将项添加到IEnumerable

时间:2011-02-17 08:14:14

标签: c# ienumerable

我有一个List<>我的对象,但现在需要将其更改为IEnumerable<>。所以,我有这个:

public IEnumerable<TransactionSplitLine> TransactionSplitLines { get; set; }

然而,我再也不能这样做了:

reply.TransactionSplitLines.Add(new TransactionSplitLine
                                                    {Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)});

我现在应该如何添加项目?

8 个答案:

答案 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<>作为此属性的内部字段并单独修改它 - 可能性是你在这里使用具体对象,不是界面。如果您正在使用该界面并仍需要使用AddIEnumerable<>只是此界面类型的错误选择。

答案 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();