I want to convert the items entered to a String list to:
System.Collections.ObjectModel.ReadOnlyCollection<string>
I have tried using:
(System.Collections.ObjectModel.ReadOnlyCollection<string>)listname
But it returns an error.
You can create a new instance using the existing List in the constructor.
var readOnlyList = new ReadOnlyCollection<string>(existingList);
ReadOnlyCollection(Of T) Constructor on MSDN
If you've got:
List<string> names=new List<string>(){"Rod", "Jane", "Freddy"};
Then you can say:
ReadOnlyCollection<string> readOnlyNames=names.AsReadOnly();
This doesn't copy the list. Instead the readonly collection stores a reference to the original list and prohibits changing it. However, if you modify the underlying list via names then the readOnlyNames will also change, so it's best to discard the writable instance if you can.
The constructor of ReadOnlyCollection accepts an IList
Here is some reference http://msdn.microsoft.com/en-us/library/ms132476.aspx
var myreadonlycollection = new ReadOnlyCollection<string>(listname);
var readonlyCollection = new ReadOnlyCollection<string>(list);
The other answers are correct in that you need to pass an IList<T> to the constructor of a ReadOnlyCollection<T>.
I find it useful to have an extension method on IEnumerable<T> that facilitates the creation of the ReadOnlyCollection<T>:
public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(
this IEnumerable<T> source)
{
if (source == null) throw new ArgumentNullException("source");
return new ReadOnlyCollection<T>(
source as IList<T> ?? source.ToList());
}
Related
I have an IEnumerable object as:
IEnumerable<string> listSelectedItems;
Which contains three items. Now i created a new object and want to get all items from listSelectedItems, so i wrote this code:
IEnumerable<string> newList = listSelectedItems;
But now when i alter newList, the listSelectedItems also gets altered. How can i achieve altering or creating a new IEnumerable without refernce.
Are you looking for this?
IEnumerable<string> newList = listSelectedItems.ToList();
IEnumerable is an interface, so you can't instantiate it, you need an implementation of it, for example List
IEnumerable<string> newList = new List<string>(listSelectedItems);
In your case setting newList = listSelectedItems means that newList will be just a reference to the listSelectedItems so if the underlying object is changed, newList will reference the changed object.
I'm wondering how one can prove what the .Net framework is doing behind the scenes.
I have a method that accepts a parameter of a List<String> originalParameterList.
In my method I have another List<String> newListObj if I do the following:
List<String> newListObj = originalParameterList
newListObj.Add(value);
newListObj.Add(value1);
newListObj.Add(value2);
The count of the originalParameterList grows (+3).
If I do this:
List<String> newListObj = new List<String>(originalParamterList);
newListObj.Add(value);
newListObj.Add(value1);
newListObj.Add(value2);
The count of the originalParameterList stays the sames (+0).
I also found that this code behaves the same:
List<String> newListObj = new List<String>(originalParamterList.ToArray());
newListObj.Add(value);
newListObj.Add(value1);
newListObj.Add(value2);
The count of the originalParameterList stays the sames (+0).
My question is, is there a way to see what the .Net Framework is doing behind the scenes in a definitive way?
You can load your assembly into ILDASM and(when loaded),find your method and double-click it,
it will show the cil code of that method.Just type "IL" in windows start menu in the search.
Alternatively you can you can use these following ways to also create a new independent list
private void GetList(List<string> lst)
{
List<string> NewList = lst.Cast<string>().ToList();
NewList.Add("6");
//not same values.
//or....
List<string> NewList = lst.ConvertAll(s => s);
NewList.Add("6");
//again different values
}
Normally, the documentation should give enough information to use the API.
In your specific example, the documentation for public List(IEnumerable<T> collection) says (emphasis mine):
Initializes a new instance of the List class that contains elements
copied from the specified collection and has sufficient capacity to
accommodate the number of elements copied.
For the reference here is the source code for the constructor:
public List (IEnumerable <T> collection)
{
if (collection == null)
throw new ArgumentNullException ("collection");
// initialize to needed size (if determinable)
ICollection <T> c = collection as ICollection <T>;
if (c == null) {
_items = EmptyArray<T>.Value;;
AddEnumerable (collection);
} else {
_size = c.Count;
_items = new T [Math.Max (_size, DefaultCapacity)];
c.CopyTo (_items, 0);
}
}
void AddEnumerable (IEnumerable <T> enumerable)
{
foreach (T t in enumerable)
{
Add (t);
}
}
The simplest way to do it is simply go to MSDN
http://msdn.microsoft.com/en-us/library/fkbw11z0.aspx
It says that
Initializes a new instance of the List class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
so internally it`s simply add all elements of passed IEnumerable into new list. It also says that
this is a O(n) operation
which means that no optimizations assumed.
That's because the frist case you referenced the original list (since it is a reference type), and you modified it's collection via newListObj. The second and third case you copied the original objects' collection via List constructor List Class, and you modified the new collection, which is not take any effect to the original.
As others already said, there are various tools that let you examine the source code of the .NET framework. I personally prefer dotPeek from JetBrains, which is free.
In the specific case that you have mentioned, I think when you pass a list into the constructor of another list, that list is copied. If you just assign one variable to another, those variables are then simply referring to the same list.
You can either
read the documentation over at MSDN
decompile the resulting MSIL-code, for instance using Telerik's free JustDecompile
or step through the .NET Framework code using the debugger.
This is the code from List constrcutor:
public List(IEnumerable<T> collection)
{
if (collection == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
}
ICollection<T> collection2 = collection as ICollection<T>;
if (collection2 != null)
{
int count = collection2.Count;
this._items = new T[count];
collection2.CopyTo(this._items, 0);
this._size = count;
return;
}
this._size = 0;
this._items = new T[4];
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Add(enumerator.Current);
}
}
}
As you can see when you calls costructor which takes IEnumerable it copies all data to itself.
Here's how I would add one item to an IEnumerable object:
//Some IEnumerable<T> object
IEnumerable<string> arr = new string[] { "ABC", "DEF", "GHI" };
//Add one item
arr = arr.Concat(new string[] { "JKL" });
This is awkward. I don't see a method called something like ConcatSingle() however.
Is there a cleaner way to add a single item to an IEnumerable object?
Nope, that's about as concise as you'll get using built-in language/framework features.
You could always create an extension method if you prefer:
arr = arr.Append("JKL");
// or
arr = arr.Append("123", "456");
// or
arr = arr.Append("MNO", "PQR", "STU", "VWY", "etc", "...");
// ...
public static class EnumerableExtensions
{
public static IEnumerable<T> Append<T>(
this IEnumerable<T> source, params T[] tail)
{
return source.Concat(tail);
}
}
IEnumerable is immutable collection, it means you cannot add, or remove item. Instead, you have to create a new collection for this, simply to convert to list to add:
var newCollection = arr.ToList();
newCollection.Add("JKL"); //is your new collection with the item added
Write an extension method ConcatSingle :)
public static IEnumerable<T> ConcatSingle<T>(this IEnumerable<T> source, T item)
{
return source.Concat(new [] { item } );
}
But you need to be more careful with your terminology.
You can't add an item to an IEnumerable<T>. Concat creates a new instance.
Example:
var items = Enumerable.Range<int>(1, 10)
Console.WriteLine(items.Count()); // 10
var original= items;
items = items.ConcatSingle(11);
Console.WriteLine(original.Count()); // 10
Console.WriteLine(items.Count()); // 11
As you can see, the original enumeration - which we saved in original didn't change.
Since IEnumerable is read-only, you need to convert to list.
var new_one = arr.ToList().Add("JKL");
Or you can get a extension method like;
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] item)
{
return source.Concat(item);
}
Append() - is exactly what you need, it has been added to the .NET Standard (in 2017), so you no longer need to write your own extension methods. You can simply do this:
arr = arr.Append("JKL");
Since .NET is open source, here you can look on the implementation (it is more sophisticated than custom methods suggested above):
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/AppendPrepend.cs
You're assigning an array to an IEnumerable. Why don't you use the Array type instead of IEnumerable?
Otherwise you can use IList (or List) if you want to change the collection.
I use IEnumerable only for methods params when I need to read and IList (or List) when I need to change items in it.
I have a collection of anonymous class and I want to return an empty list of it.
What is the best readable expression to use?
I though of the following but I don't think they are readably enough:
var result = MyCollection.Take(0).ToList();
var result = MyCollection.Where(p => false).ToList();
Note: I don't want to empty the collection itself.
Any suggestion!
Whats about:
Enumerable.Empty<T>();
This returns an empty enumerable which is of type T. If you really want a List so you are free to do this:
Enumerable.Empty<T>().ToList<T>();
Actually, if you use a generic extension you don't even have to use any Linq to achieve this, you already have the anonymous type exposed through T
public static IList<T> GetEmptyList<T>(this IEnumerable<T> source)
{
return new List<T>();
}
var emp = MyCollection.GetEmptyList();
Given that your first suggestion works and should perform well - if readability is the only issue, why not create an extension method:
public static IList<T> CreateEmptyCopy(this IEnumerable<T> source)
{
return source.Take(0).ToList();
}
Now you can refactor your example to
var result = MyCollection.CreateEmptyCopy();
For performance reasons, you should stick with the first option you came up with.
The other one would iterate over the entire collection before returning an empty list.
Because the anonymous type there is no way, in source code, to create a list. There is, however, a way to create such list through reflection.
I've created a generic function as below (just a s a proof) that will take a List<T> collection and reverse it, returning a new List<T> as its output.
public static List<T> ReverseList<T>(List<T> sourceList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
return outputArray.Reverse().ToList();
}
The purpose of the proof is that I only know what T is at runtime. I am therefore using reflection to call the above method as follows:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5 }; // As an example, but could be any type for T
MethodInfo myMethod = this.GetType().GetMethod("ReverseList");
MethodInfo resultMethod = myMethod.MakeGenericMethod(new Type[] { typeof(int) });
object result = resultMethod.Invoke(null, new object[] { myList });
There are two problems here:
In the second line, rather than supplying typeof(int), I would like suppliy somthign akin to myList.GetType().GetGenericArguments()[0].GetType() in order to make things more flexible because I do not know T until runtime. Doing this results in a runtime error when the Invoke runs as follows: "Object of type 'System.Collections.Generic.List'1[System.Int32]' cannot be converted to type 'System.Collections.Generic.List'1[System.RuntimeType]'."
The result of the Invoke() method returns an object. When debugging, I can see that the object is of type List, but attempting to use it tells me that I have an invalid cast. I assume that I need to use reflection to box the result in to the correct type (i.e. in this example, the equivalent of (result as List<int>).
Does anyone have any pointers that could help me resolve this? Apologies if this is not to clear, I can probably provide more detail if asked.
TIA
You've got one GetType() too many. Happens to everyone.
myList.GetType().GetGenericArguments()[0] IS a System.Type -- the one you're looking for.
myList.GetType().GetGenericArguments()[0].GetType() is a System.Type describing System.Type (well, actually the concrete subclass System.RuntimeType).
Also, your ReverseList function is serious overkill. It does an extra copy just to avoid calling List.Reverse. There's a better way to circumvent that:
public static List<T> ReverseList<T>(List<T> sourceList)
{
return Enumerable.Reverse(sourceList).ToList();
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>(sourceList);
result.Reverse();
return result;
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>();
result.Capacity = sourceList.Count;
int i = sourceList.Count;
while (i > 0)
result.Add(sourceList[--i]);
return result;
}
To access it as a List<T>, yes you'd need to find T using reflection (probably over the interfaces, for example typeof(IList<>), and use more reflection and MakeGenericMethod etc. In all honesty, it isn't worth it: you would do better to check for the non-generic IList:
var list = result as IList;
if (list != null)
{
// loop over list etc
}
Generics ad reflection are not good friends.
Note in 4.0 there are also some tricks you can do here with dynamic and generics.
The result of the Invoke() method
returns an object. When debugging, I
can see that the object is of type
List, but attempting to use it tells
me that I have an invalid cast. I
assume that I need to use reflection
to box the result in to the correct
type (i.e. in this example, the
equivalent of (result as List).
The only workaround for this is I can think of is to pass an empty list as the second parameter of the method and to populate that list - the reference returned by Invoke() will always be only of type object, but inside the generic method you do have access to the type itself:
List<int> reverseList = new List<int>();
resultMethod.Invoke(null, new object[] { myList, reverseList });
...
public static void ReverseList<T>(List<T> sourceList, List<T> resultList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
resultList.AddRange(outputArray.Reverse());
}