What's the standard way to get a typed, readonly empty list in C#, or is there one?
ETA: For those asking "why?": I have a virtual method that returns an IList (or rather, post-answers, an IEnumerable), and the default implementation is empty. Whatever the list returns should be readonly because writing to it would be a bug, and if somebody tries to, I want to halt and catch fire immediately, rather than wait for the bug to show up in some subtle way later.
Personally, I think this is better than any of the other answers:
static readonly IList<T> EmptyList = new T[0];
Arrays implement IList<T>.
You cannot add to an array.
You cannot assign to an element in an empty array (because there is none).
This is, in my opinion, a lot simpler than new List<T>().AsReadOnly().
You still get to return an IList<T> (if you want).
Incidentally, this is what Enumerable.Empty<T>() actually uses under the hood, if I recall correctly. So theoretically you could even do (IList<T>)Enumerable.Empty<T>() (though I see no good reason to do that).
You can just create a list:
List<MyType> list = new List<MyType>();
If you want an empty IEnumerable<T>, use Enumerable.Empty<T>():
IEnumerable<MyType> collection = Enumerable.Empty<MyType>();
If you truly want a readonly list, you could do:
IList<MyType> readonlyList = (new List<MyType>()).AsReadOnly();
This returns a ReadOnlyCollection<T>, which implements IList<T>.
Starting with .net 4.6 you can also use:
IList<T> emptyList = Array.Empty<T>();
This does only create a new instance once for every different type you specify as T.
IList<T> list = new List<T>().AsReadOnly();
Or, if you want an IEnumerable<>:
IEnumerable<T> sequence = Enumerable.Empty<T>();
If you want a list whose contents can't be modified, you can do:
ReadOnlyCollection<Foo> foos = new List<Foo>().AsReadOnly();
Construct an instance of System.Collections.ObjectModel.ReadOnlyCollection from your list.
List<int> items = new List<int>();
ReadOnlyCollection<int> readOnlyItems = new ReadOnlyCollection<int>(items);
To expand on Dan Tao's answer, the following implementation can be used in the same way as Enumerable.Empty<T>(), by specifying List.Empty<T>() instead.
public static class List
{
public static IList<T> Empty<T>()
{
// Note that the static type is only instantiated when
// it is needed, and only then is the T[0] object created, once.
return EmptyArray<T>.Instance;
}
private sealed class EmptyArray<T>
{
public static readonly T[] Instance = new T[0];
}
}
Edit: I change the above code to reflect the outcome of a discussion with Dan Tao about lazy versus eager initialization of the Instance field.
What about:
readonly List<T> mylist = new List<T>();
Not sure why you want it readonly; that doesn't make much sense in most scenarios I can think of, though.
Related
I try to do something like this:
public const List<String> METRICS = new List<String>()
{
SourceFile.LOC,
SourceFile.MCCABE,
SourceFile.NOM,
SourceFile.NOA,
SourceFile.FANOUT,
SourceFile.FANIN,
SourceFile.NOPAR,
SourceFile.NDC,
SourceFile.CALLS
};
But unfortunately this doesn't work:
FileStorer.METRICS' is of type 'System.Collections.Generic.List<string>'. A const field of a reference type other than string can only be initialized with null.
How can I solve this problem?
const is for compile-time constants. You could just make it static readonly, but that would only apply to the METRICS variable itself (which should typically be Metrics instead, by .NET naming conventions). It wouldn't make the list immutable - so someone could call METRICS.Add("shouldn't be here");
You may want to use a ReadOnlyCollection<T> to wrap it. For example:
public static readonly IList<String> Metrics = new ReadOnlyCollection<string>
(new List<String> {
SourceFile.LoC, SourceFile.McCabe, SourceFile.NoM,
SourceFile.NoA, SourceFile.FanOut, SourceFile.FanIn,
SourceFile.Par, SourceFile.Ndc, SourceFile.Calls });
ReadOnlyCollection<T> just wraps a potentially-mutable collection, but as nothing else will have access to the List<T> afterwards, you can regard the overall collection as immutable.
(The capitalization here is mostly guesswork - using fuller names would make them clearer, IMO.)
Whether you declare it as IList<string>, IEnumerable<string>, ReadOnlyCollection<string> or something else is up to you... if you expect that it should only be treated as a sequence, then IEnumerable<string> would probably be most appropriate. If the order matters and you want people to be able to access it by index, IList<T> may be appropriate. If you want to make the immutability apparent, declaring it as ReadOnlyCollection<T> could be handy - but inflexible.
You'll need to use a static readonly list instead. And if you want the list to be immutable then you might want to consider using ReadOnlyCollection<T> rather than List<T>.
private static readonly ReadOnlyCollection<string> _metrics =
new ReadOnlyCollection<string>(new[]
{
SourceFile.LOC,
SourceFile.MCCABE,
SourceFile.NOM,
SourceFile.NOA,
SourceFile.FANOUT,
SourceFile.FANIN,
SourceFile.NOPAR,
SourceFile.NDC,
SourceFile.CALLS
});
public static ReadOnlyCollection<string> Metrics
{
get { return _metrics; }
}
You are looking for a simple code, like this:
List<string> tagList = new List<string>(new[]
{
"A"
,"B"
,"C"
,"D"
,"E"
});
I want to create a new instance of an object IEnumerable<object>
Can I do this?
IEnumerable<object> a = new IEnumerable<object>();
You can for example create an instance of List<object>, which implements IEnumerable<object>. Example:
List<object> list = new List<object>();
list.Add(1);
list.Add(4);
list.Add(5);
IEnumerable<object> en = list;
CallFunction(en);
Another solution would be to use Empty<T>.
msdn extract:
Returns an empty IEnumerable that has the specified type argument.
IEnumerable<object> a = Enumerable.Empty<object>();
There is a thread on SO about it: Is it better to use Enumerable.Empty() as opposed to new List to initialize an IEnumerable?
If you use an empty array or empty list, those are objects and they are stored in memory. The Garbage Collector has to take care of them. If you are dealing with a high throughput application, it could be a noticeable impact.
Enumerable.Empty does not create an object per call thus putting less load on the GC.
Since you now specified you want to add to it, what you want isn't a simple IEnumerable<T> but at least an ICollection<T>. I recommend simply using a List<T> like this:
List<object> myList=new List<object>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
You can use myList everywhere an IEnumerable<object> is expected, since List<object> implements IEnumerable<object>.
(old answer before clarification)
You can't create an instance of IEnumerable<T> since it's a normal interface(It's sometimes possible to specify a default implementation, but that's usually used only with COM).
So what you really want is instantiate a class that implements the interface IEnumerable<T>. The behavior varies depending on which class you choose.
For an empty sequence use:
IEnumerable<object> e0=Enumerable.Empty<object>();
For an non empty enumerable you can use some collection that implements IEnumerable<T>. Common choices are the array T[], List<T> or if you want immutability ReadOnlyCollection<T>.
IEnumerable<object> e1=new object[]{1,2,3};
IEnumerable<object> e2=new List<object>(){1,2,3};
IEnumerable<object> e3=new ReadOnlyCollection(new object[]{1,2,3});
Another common way to implement IEnumerable<T> is the iterator feature introduced in C# 3:
IEnumerable<object> MyIterator()
{
yield return 1;
yield return 2;
yield return 3;
}
IEnumerable<object> e4=MyIterator();
No you can't since IEnumerable is an interface.
You should be able to create an empty instance of most non-interface types which implement IEnumerable, e.g.:-
IEnumerable<object> a = new object[] { };
or
IEnumerable<object> a = new List<object>();
No, You cannot do that. Use the following line of code instead:
IEnumerable<int> usersIds = new List<int>() {1, 2, 3}.AsEnumerable();
I hope it helps.
The main reason is we can't create object of an interface, and IEnumerable is an interface.
We need to create object of the class which implements the interface. This is the main reason we can't directly create object of IEnumerable.
You can do this:
IEnumerable<object> list = new List<object>(){1, 4, 5}.AsEnumerable();
CallFunction(list);
I wanted to create a new enumerable object or list and be able to add to it.
This comment changes everything. You can't add to a generic IEnumerable<T>. If you want to stay with the interfaces in System.Collections.Generic, you need to use a class that implements ICollection<T> like List<T>.
No IEnumerable is an interface, you can't create instance of interface
you can do something like this
IEnumerable<object> a = new object[0];
It's a pretty old question, but for the sake of newcomers, this is how we can protect an IEnumerable<T> from a null exception. Another word, to create an empty instance of a variable of type IEnumerable<T>
public IEnumerable<T> MyPropertyName { get; set; } = Enumerable.Empty<T>();
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.empty?view=net-5.0
Cheers.
I have been Implementing IEnumerable of type IEnumerable<T> by this way
IEnumerable<T> MyEnum = new T[]{ /*object of type T*/ };
Example:
var Object = new Book{id = 1,name = "Hello World"};
IEnumerable<Book> MyEnum = new Book[]{ Object };
As the easiest way to convert the IList<T1> to IList<BaseT1>?
IList<T1>.Count() is very large number!!!
class BaseT1 { };
class T1 : BaseT1
{
static public IList<BaseT1> convert(IList<T1> p)
{
IList<BaseT1> result = new List<BaseT1>();
foreach (BaseT1 baseT1 in p)
result.Add(baseT1);
return result;
}
}
You'll get much better performance in your implementation if you specify the size of the result list when it is initalized, and call the Add method on List<T> directly:
List<BaseT1> result = new List<BaseT1>(p.Count);
that way, it isn't resizing lots of arrays when new items get added. That should yield an order-of-magnitude speedup.
Alternatively, you could code a wrapper class that implements IList<BaseT1> and takes an IList<T1> in the constructor.
linq?
var baseList = derivedList.Cast<TBase>();
Edit:
Cast returns an IEnumerable, do you need it in a List? List can be an expensive class to deal with
IList<T1>.Count() is very large number!!!
Yes, which means that no matter what syntax sugar you use, the conversion is going to require O(n) time and O(n) storage. You cannot cast the list to avoid re-creating it. If that was possible, client code could add an element of BaseT1 to the list, violating the promise that list only contains objects that are compatible with T1.
The only way to get ahead is to return an interface type that cannot change the list. Which would be IEnumerable<BaseT1> in this case. Allowing you to iterate the list, nothing else. That conversion is automatic in .NET 4.0 thanks to its support for covariance. You'll have to write a little glue code in earlier versions:
public static IEnumerable<BaseT1> enumerate(IList<T1> p) {
foreach (BaseT1 item in p) yield return item;
}
I have a custom list which inherits from Generic.List<T> like this:
public class TransferFileList<T> : List<TransferFile> { .. }
When I set (where 'Files' is a TransferFileList<T>):
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
the 'files' object resolves as System.Collections.Generic.List<TransferFile>, not TransferFileList<T>, which is what I would expect as it was what was being filtered through the Where, so how could I successfully return a list of TransferFileList<T> into 'files'?
I did try:
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
as TransferFileList<TransferFile>;
but using that safe cast, it just resolves as null.
Thanks guys and gals.
First, I have to ask why you are inheriting from List<T>? 99% of the time that's a bad idea.
If you want to extend the functionality of a list, use extension methods:
public static something PrintErrors(this List<TransferFile> list)
{
//do your printing logic
}
On to the answer: ToList() operates on an IEnumerable<T> and converts the members of the sequence to a List of the same type. Since you inherit from List<T> which implements IEnumerable<T>, that's what happens there.
Where() works the same way - operates on an IEnumerable<T> and returns an IEnumerable<T>.
To get some arbitrary list-like object back, like you have, you need to add the items in a sequence to your custom list, like so:
var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));
You can add an extension method for IEnumerable<TransferFile> to handle that scenario:
public static TransferFileList ToTransferFileList(
this IEnumerable<TransferFile> files)
{
return new TransferFileList(files);
}
// ...
var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList();
This provides you with the TransferFileList instead of just a List<TransferFile>. Note the reason your as returns null is because while TransferFileList is a List<TransferFile>, the same does not hold in the other direction. That is, your List<TransferFile> is NOT a TransferFileList object.
I agree with #RexM that any attempt at subclassing List<T> be avoided due to the multitude of pitfalls associated. I suggest Composition (Has-A rather than Is-A) or sticking with the base class library collections instead.
Thanks guys.
I like SLV's extension approach, but is there any other straight casting approach?
If not I might just go with the reverted in-line approach I was hoping to avoid:
var transferFiles = new TransferFileList<TransferFile>();
if (files != null)
transferFiles.AddRange(files);
My question as title above. For example
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
but after all it only has 1 item inside. Can we have a method like items.Add(item) like the List<T>?
You cannot, because IEnumerable<T> does not necessarily represent a collection to which items can be added. In fact, it does not necessarily represent a collection at all! For example:
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??
What you can do, however, is create a new IEnumerable object (of unspecified type), which, when enumerated, will provide all items of the old one, plus some of your own. You use Enumerable.Concat for that:
items = items.Concat(new[] { "foo" });
This will not change the array object (you cannot insert items into to arrays, anyway). But it will create a new object that will list all items in the array, and then "Foo". Furthermore, that new object will keep track of changes in the array (i.e. whenever you enumerate it, you'll see the current values of items).
The type IEnumerable<T> does not support such operations. The purpose of the IEnumerable<T> interface is to allow a consumer to view the contents of a collection. Not to modify the values.
When you do operations like .ToList().Add() you are creating a new List<T> and adding a value to that list. It has no connection to the original list.
What you can do is use the Add extension method to create a new IEnumerable<T> with the added value.
items = items.Add("msg2");
Even in this case it won't modify the original IEnumerable<T> object. This can be verified by holding a reference to it. For example
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
After this set of operations the variable temp will still only reference an enumerable with a single element "foo" in the set of values while items will reference a different enumerable with values "foo" and "bar".
EDIT
I contstantly forget that Add is not a typical extension method on IEnumerable<T> because it's one of the first ones that I end up defining. Here it is
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
Have you considered using ICollection<T> or IList<T> interfaces instead, they exist for the very reason that you want to have an Add method on an IEnumerable<T>.
IEnumerable<T> is used to 'mark' a type as being...well, enumerable or just a sequence of items without necessarily making any guarantees of whether the real underlying object supports adding/removing of items. Also remember that these interfaces implement IEnumerable<T> so you get all the extensions methods that you get with IEnumerable<T> as well.
In .net Core, there is a method Enumerable.Append that does exactly that.
The source code of the method is available on GitHub..... The implementation (more sophisticated than the suggestions in other answers) is worth a look :).
A couple short, sweet extension methods on IEnumerable and IEnumerable<T> do it for me:
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);
}
Elegant (well, except for the non-generic versions). Too bad these methods are not in the BCL.
No, the IEnumerable doesn't support adding items to it. The alternative solution is
var myList = new List(items);
myList.Add(otherItem);
To add second message you need to -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
I just come here to say that, aside from Enumerable.Concat extension method, there seems to be another method named Enumerable.Append in .NET Core 1.1.1. The latter allows you to concatenate a single item to an existing sequence. So Aamol's answer can also be written as
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
Still, please note that this function will not change the input sequence, it just return a wrapper that put the given sequence and the appended item together.
Not only can you not add items like you state, but if you add an item to a List<T> (or pretty much any other non-read only collection) that you have an existing enumerator for, the enumerator is invalidated (throws InvalidOperationException from then on).
If you are aggregating results from some type of data query, you can use the Concat extension method:
Edit: I originally used the Union extension in the example, which is not really correct. My application uses it extensively to make sure overlapping queries don't duplicate results.
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
Others have already given great explanations regarding why you can not (and should not!) be able to add items to an IEnumerable. I will only add that if you are looking to continue coding to an interface that represents a collection and want an add method, you should code to ICollection or IList. As an added bonanza, these interfaces implement IEnumerable.
you can do this.
//Create IEnumerable
IEnumerable<T> items = new T[]{new T("msg")};
//Convert to list.
List<T> list = items.ToList();
//Add new item to list.
list.add(new T("msg2"));
//Cast list to IEnumerable
items = (IEnumerable<T>)items;
Easyest way to do that is simply
IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");
Then you can return list as IEnumerable also because it implements IEnumerable interface
Instances implementing IEnumerable and IEnumerator (returned from IEnumerable) don't have any APIs that allow altering collection, the interface give read-only APIs.
The 2 ways to actually alter the collection:
If the instance happens to be some collection with write API (e.g. List) you can try casting to this type:
IList<string> list = enumerableInstance as IList<string>;
Create a list from IEnumerable (e.g. via LINQ extension method toList():
var list = enumerableInstance.toList();
IEnumerable items = Enumerable.Empty(T);
List somevalues = new List();
items.ToList().Add(someValues);
items.ToList().AddRange(someValues);
Sorry for reviving really old question but as it is listed among first google search results I assume that some people keep landing here.
Among a lot of answers, some of them really valuable and well explained, I would like to add a different point of vue as, to me, the problem has not be well identified.
You are declaring a variable which stores data, you need it to be able to change by adding items to it ? So you shouldn't use declare it as IEnumerable.
As proposed by #NightOwl888
For this example, just declare IList instead of IEnumerable: IList items = new T[]{new T("msg")}; items.Add(new T("msg2"));
Trying to bypass the declared interface limitations only shows that you made the wrong choice.
Beyond this, all methods that are proposed to implement things that already exists in other implementations should be deconsidered.
Classes and interfaces that let you add items already exists. Why always recreate things that are already done elsewhere ?
This kind of consideration is a goal of abstracting variables capabilities within interfaces.
TL;DR : IMO these are cleanest ways to do what you need :
// 1st choice : Changing declaration
IList<T> variable = new T[] { };
variable.Add(new T());
// 2nd choice : Changing instantiation, letting the framework taking care of declaration
var variable = new List<T> { };
variable.Add(new T());
When you'll need to use variable as an IEnumerable, you'll be able to. When you'll need to use it as an array, you'll be able to call 'ToArray()', it really always should be that simple. No extension method needed, casts only when really needed, ability to use LinQ on your variable, etc ...
Stop doing weird and/or complex things because you only made a mistake when declaring/instantiating.
Maybe I'm too late but I hope it helps anyone in the future.
You can use the insert function to add an item at a specific index.
list.insert(0, item);
Sure, you can (I am leaving your T-business aside):
public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
List<string> list = items.ToList();
string obj = "";
list.Add(obj);
return list.Select(i => i);
}