Adding an item to IEnumerable

天大地大妈咪最大 提交于 2021-02-18 11:20:09

问题


I had a List<> of my objects, but now need to change it to an IEnumerable<>. So, I have this:

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

However, I can no longer do:

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

How should I be adding items now?


回答1:


You could do something like the following, using Concat:

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

That basically creates a new IEnumerable. It's hard to say what's the best solution in your case, since there are not enough information about your use case.

EDIT: Please note that List<T> implements IEnumerable<T>. So if you need to pass an IEnumerable<T> as a parameter for example, you can also pass a List<T> instead, maybe calling explicitly AsEnumerable() on your list first. So maybe you could stick with a List instead of an IEnumerable.




回答2:


Short answer: You can't add items to IEnumerable<T>

Slightly longer explanation:

IEnumerable is an interface that is solely concerned about being able to enumerate/iterate over the collection of items. This is the only purpose of an existence of IEnumerable. It abstracts away any notion of the manner of storing or retrieving the enumerable items (it might be a string of characters, list of items, a stream of bytes or series of a computation results), thus if you have an interface that is an IEnumerable, you can't add items to it, you can only iterate across the items it provides.

That said, the correct way to add items to IEnumerable is to return new IEnumerable with the new items appended to the contents of the original.

Also with Linq libraries you have an extension method that allows casting your IEnumerable to a List via IEnumerable.ToList() and you can add items to a list. THis moght not be the proper way though.

With Linq libraries in your namespace you can do the following:

using System;
using System.Collections.Generic;
using System.Linq;

namespace EnumTester
{
    class Program
    {
        static void Main(string[] args)
        {
             IEnumerable<string> enum = GetObjectEnumerable();

             IEnumerable<string> concatenated = enum.Concat(new List<string> { "concatenated" });

             List<string> stringList = concatenated.ToList();
        }
    }
}



回答3:


You cannot add items to IEnumerable<T> since this interface does not have an Add method.
if TransactionSplitLines always return an instance of a List<TransactionSplitLine> you might want to change its type to IList<TransactionSplitLine>.
In case you cannot change the type of TransactionSplitLines and you can guarantee that it is always return a IList<TransactionSplitLines> you can cast it as in

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



回答4:


IEnumerable<T> doesn't have an Add(T) method. Depending on your real type, you could cast it like this:

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

((IList)reply.TransactionSplitLines).Add(item);

If the collection you are using implements IList.

Remember that you want to use most basic Interface / Class when you pass your objects around. So if you need to use methods from IList I would suggest you use that instead of IEnumerable.

I would suggest you do the following Change:

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



回答5:


It depends on what is the meaning and purpose of your TransactionSplitLines property.

If you want to allow editing (adding/removing) from the outside of you class, well just make your property less generic than IEnumerable<T> for example:

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

or better:

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

Instead, if you need just to edit the collection internally (I mean in the class scope), why don't you do something like this:

private List<TransactionSplitLine> transactionSplitLines;

public IEnumerable<TransactionSplitLine> TransactionSplitLines 
{ 
  get
  {
     return transactionSplitLines;
  }
}

so you can use transactionSplitLines field to change the collection internally.




回答6:


I would create this extension method, which does all that lazily:

public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] items)
{
    return source.Concat(items);
}

So in your case:

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

You can have Prepend as well similarly:

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] items)
{
    return items.Concat(source);
}



回答7:


You could use the Concat method for concatenating two sets like that:

reply.TransactionSplitlines = reply.TransactionSplitlines.Concat(/* another enumerable */);

You would need to write an extension method AsEnumerable which would take an obj and do something like yield return obj;. You can avoid writing an extension method and just pass new [] with an object in it to the Concat method, but if your interface is based on IEnumerable, it's likely that you'll need the AsEnumerable method in some other cases too.

That's if you really need it to be IEnumerable. However, I would advise to consider switching to IList<T> or some other interface that supports add. If you need to implement some interface by having the IEnumerable<> property, you can have the IList<> as an inner field for this property and modify it separately - the odds are that you are working with concrete object here, not the interface. If you are working with the interface and still need to use Add, IEnumerable<> is just a bad choice of type for this interface.




回答8:


IEnumerable is immutable collection, it means you cannot add, or remove item. Extension method creates a new instance.(Explained with an eg here: What's the Best Way to Add One Item to an IEnumerable<T>? ) Rather, then creating Extension method, one can initially add to list like below: eg In my case User Roles are defined as IEnumerable(in User model class). So, in order to add in value to that Role. Initially I had defined a list :

List<Role> rols=new List<Role>();

Inside for loop added value to this list like:

foreach(int i=0;i<chkRoles.count;i++)
{
 Role r=new Role();
r.RoleId="2";
r.RoleName="Admin";
rols.add(r);
}

and then provide this value to IEnumerable ist:

user.Roles=rols.AsEnumerable();


来源:https://stackoverflow.com/questions/5026483/adding-an-item-to-ienumerable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!