问题
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