Difference between ReadOnlyCollection string[] in the context of collection - c#

IList<string> strList = new string[] { "Apple", "Mango", "Orange" };
IList<string> lst = new ReadOnlyCollection<string>(new[]{"Google",
"MSN","Yahoo"});
In both cases i can not use "Add()" method for adding new items.then almost both
declarations are same?

With the first, strList[2] = "Pear"; will work... not with the second. Arrays are always mutable in that you can re-assign by index, even if you can't add/remove. A read-only-collection is just that: read-only.

The items in strList can be changed (not added or removed, but changed).

In the first declaration, you can still use the following:
strList[0] = "Not a fruit";
ReadOnlyCollection<T> wraps any IList<T> in a lightweight object. It passes all calls that wouldn't change the collection on to the wrapped object (get Count, get Item[], GetEnumerator), but throws an exception for all calls that would change the collection (Add, Remove, Clear, set Item[]).
Arrays are not resizable, but they are not readonly. The distinction is important to understand or you can introduce some serious security issues, for an example see Path.InvalidPathChars Field.

Related

Creating an IReadOnlyList<string>

How do I create an IReadOnlyList<string> with some values in it?
I found an example of ReadOnlyCollection which seems to convert an existing collection to an ReadOnlyCollection but that approach didn't work.
Here's what I tried:
var myList = new List<string>()
{
"Hello World!",
"Some more text here"
};
var myReadOnlyList = new IReadOnlyList<string>(myList);
I also tried adding my string values into an IReadOnlyList<string> during declaration but that didn't work either.
What's the right way to create a IReadOnlyList<string>() with some values in it?
IReadOnlyList<string>, despite the name, just means "list you can read", it doesn't mean "immutable list". Whether the list is immutable depends on the concrete class that will end up implementing the interface.
Therefore, what you should do depends on your needs.
IReadOnlyList<string> myReadOnlyList = myList;. This works because List<string> implements IReadOnlyList<string>. It does not prevent others from casting myReadOnlyList back to List<string>.
IReadOnlyList<string> myReadOnlyList = myList.AsReadOnly();. This creates a read-only proxy for the original list. Although it does prevent others from casting myReadOnlyList back to List<string>, the contents of myReadOnlyList may still change as a result of modifications on myList.
IReadOnlyList<string> myReadOnlyList = ImmutableList.CreateRange(myList); This creates an ImmutableList<string> which contains copies of the original list's contents and does not allow any modification. Changes to myList won't be visible in myReadOnlyList.
Try this:
List<string> listData = new List<string>();
public IReadOnlyList<string> readOnlyData = listData.AsReadOnly();
And here's an example on how to use it:
string text = readOnlyData[0];
Note: Make sure that you add to listData before you assign it to readOnlyData.

Is there any subtle difference between inline initializing a list with or without '()'?

E.g. is there any technical difference between invoking:
List<string> list = new List<T> () { "one", "two", "tree" }; // with ()
and
List<string> list = new List<T> { "one", "two", "tree" }; // without ()
?
The result is obviously the same. But I am interested if there is any technical difference in the way of invocation or this is only a convenience .NET C# shortcut.
There is no difference. The parenthesis are not required when using a collection initializer with the default constructor. However, if you want to use another constructor you cannot omit the parenthesis.
Some code refactoring tools like ReSharper will indicate this by showing the parenthesis as redundant.
Collection initializers are not limited to "built-in" .NET types. A type implementing IEnumerable and providing a suitable Add method can use a collection initializer.
Both will actualy compile into
List<string> list;
List<string> temp;
temp = new List<string>();
temp.Add("one");
temp.Add("two");
temp.Add("tree");
list = temp;
if you check generated IL code.

How to remove items in IEnumerable<MyClass>?

How do I remove items from a IEnumerable that match specific criteria?
RemoveAll() does not apply.
You can't; IEnumerable as an interface does not support removal.
If your IEnumerable instance is actually of a type that supports removal (such as List<T>) then you can cast to that type and use the Remove method.
Alternatively you can copy items to a different IEnumerable based on your criteria, or you can use a lazy-evaluated query (such as with Linq's .Where) to filter your IEnumerable on the fly. Neither of these will affect your original container, though.
This will produce a new collection rather than modifying the existing one however I think it is the idiomatic way to do it with LINQ.
var filtered = myCollection.Where(x => x.SomeProp != SomValue);
Another option would be to use Where to produce a new IEnumerable<T> with references to the objects you want removed then pass that to a Remove call on the original collection. Of course that would actually consume more resources.
You can't remove items from an IEnumerable<T>. You can remove items from an ICollection<T> or filter items from an IEnumerable<T>.
// filtering example; does not modify oldEnumerable itself
var filteredEnumerable = oldEnumerable.Where(...);
// removing example
var coll = (ICollection<MyClass>)oldEnumerable;
coll.Remove(item);
You don't remove items from an IEnumerable. It's not possible. It's just a sequence of items. You can remove items from some underlying source that generates the sequences, for example if the IEnumerable is based on a list you can remove items from that list.
The other option you have is to create a new sequence, based on this one, that never shows the given items. You can do that using Where, but it's important to realize this isn't removing items, but rather choosing to show items based on a certain condition.
As everyone has already stated, you can't remove from IEnumerable because that is not what the interface is describing. Consider the following example:
public IEnumerable<string> GetSomeStrings()
{
yield return "FirstString";
yield return "Another string";
}
Clearly, removing an element from this IEnumerable is not something you can reasonably do, instead you'd have to make a new enumeration without the ones you don't want.
The yield keywork provides other examples, for example, you can have infinite lists:
public IEnumberable<int> GetPowersOf2()
{
int value = 1;
while(true)
{
yield return value;
value = value * 2;
}
}
Items cannot be removed from an IEnumerable<T>. From the documentation:
Exposes the enumerator, which supports a simple iteration over a collection of a specified type.
You can cast it and use the List<T>.RemoveAll(Predicate<T> match) this is exactly what you need.
This is how i do,
IEnumerable<T> myVar=getSomeData(); // Assume mayVar holds some data
myVar=myVar.Where(d=>d.Id>10); // thats all, i want data with Id>10 only
How about trying Enumerable.Empty i.e.
T obj = new T();
IEnumerable<T> myVar = new T[]{obj} //Now myVar has an element
myVar = Enumerable.Empty<T>(); //Now myVar is empty

How do I create a shallow copy of an IEnumerable<T>?

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.

If method returns interface type, why can't I pass the result to a concrete type?

The question maybe a little confusing, but it's hard to make clear this question in a subject title.
I have method declared and implemented like this:
public IList<string> GetBookTitles()
{
IList<string> bookTitles = new List<string>();
// do something to populate the bookTitles list.
return bookTitles;
}
Why can't I pass the result of this method to a List<string>? After all, List<string> is a kind of IList<string>.
Well, for starters, just look at the members of IList and compare it with List. List has methods that an IList doesn't. (List has a BinarySearch method that IList doesn't, just as a single example.)
Arrays also implement IList, as an example. An array however is not a List, so you can't, and shouldn't, be able to pass a string[] to a method that accepts a List<string>.
You have a few possible solutions. One would be to just change your method to return a List<string> rather than an IList<string> (that's what I'd suggest). If that's what you really need then you shouldn't be restricting the return type to IList<string>. Another (poorer) option would be to cast the result back to a List<string> before passing it to the next method, since you happen to know that it's what the underlying type really is.
After all, List<string> is a kind of IList<string>.
But there are also other kinds of IList<String>.
What if your method were to return an IList<String> which is a ReadOnlyCollection<String> instead?
IList<string> x = new ReadOnlyCollection<string>();
List<string> y = x; //Huh?
The compiler uses the signature of your methods, not the implementation when deciding if you can assign the result of GetBookTitles to your variable, so it can't know that the result will in fact be a List. If it would allow you to do such a thing, then you could write something like this:
List<string> myBooks = GetBookTitles();
myBooks.Sort();
In your example you could do this, and in fact you can if you cast the result of your method:
List<string> myBooks = (List<string>)GetBookTitles();
But then one day you could decide that your book collection is not modifiable, and you rewrite your method as follows:
public IList<string> GetBookTitles()
{
IList<string> tmp = new List<string>();
// do something to populate the bookTitles list.
IList<string> bookTitles = new ReadOnlyCollection<string>(tmp);
return bookTitles;
}
ReadOnlyCollection does not implement Sort, so your app would compile, but would crash at runtime.
Using the cast approach it would crash when trying to do the cast, but in this case you are taking the responsibility of deciding that that kind of cast is feasible and do not have the compiler trying to guess.
A better approach could be to use as instead of the cast and chek for null. I.e.:
List<string> myBooks = GetBookTitles() as List<string>;
if (myBooks != null)
myBooks.Sort();
You should be able to, you just need an explicit conversion.
List<string> foo = (List<string>)GetBookTitles()
should do it.
The interface may be implemented in various classes which are not same. So, it will be difficult to find the respective class.
You can type cast from IList to List!!!

Categories

Resources