Stop other classes from adding to lists with "private set;" - c#

Currently, I have a class (classB) that has a list --v
class classB
{
public List<int> alist { get; private set; }
...
And I can accessing this class from another class (classA)
ClassB foo = new ClassB();
foo.alist.Add(5);
Question is, can I stop this from happening? (make it unchangeable from other classes) Thanks!

Just expose the IReadOnlyList<T> interface:
private List<int> alist;
public IReadOnlyList<int> Alist
{
get { return this.alist; }
}
From inside of the class, you continue to use "alist", to add/remove elements. From outside of the class you can only access "Alist", which doesn't allow to modify the collection (unless explicitly cast).

Well, there are various options here.
You could change the property type to one which only provides a read-only interface (e.g. IReadOnlyList<T> or IEnumerable<T>. That doesn't stop the caller from casting the returned reference back to List<T> though.
You could create a ReadOnlyCollection<T> to wrap your real list, and only expose that - that wrapper will prevent the caller from being able to access the real list at all (other than by reflection)
If your code doesn't need to modify the collection either, you could just keep the ReadOnlyCollection<T> wrapper, or use the immutable collections package
You could avoid exposing the list at all, perhaps implementing IEnumerable<T> within your class
It really depends on exactly what your requirements are.

Related

Return a list of a subtype as a List of supertype in C#

I want to make "somehow" the following work:
public class GenericsTest<T> where T: ISomeInterface
{
private List<T> someList = new List<T>();
public List<ISomeInterface> GetList()
{
return someList; //of course this doesn't even compile
}
}
Is there a way to do this (like the wildcards in Java) and I just missed it? Or it just can't be done?
EDIT:
First of all thank you all for the interest and your answers/comments. Second, sure there are ways to do that, and probably the simplest and most performance effective (not sure for that though) is to create a new list of the proper type and iteratively add the elements of the other list (someList in our case). Question is with all those new variance things, the "ins" and the "outs" if there is a way to do it the "generics way". In Java that could be:
public class GenericsTest<T extends SomeInterface> {
private List<T> someList = new ArrayList<>();
public List<? extends SomeInterface> getList() {
return someList;
}
}
So I was wandering if there is the ? extends equivalent in C#. I could accept a "no" as a short answer, I just thought I should ask first.
EDIT 2:
Some users believe and some others insist that this is a duplicate of a question that has to do with casting. Since I marked the most suitable for me answer, for the sake of clarity I explain. Guys, I don't want to cast. I am simply looking for an equivalent of the Java wildcard with the extends constraint. Of course Java has compile time only generics, which might make the difference. If the equivalent in C# is done with casting fine, but I am aware of the problem of "having a Dog object in Cat list", so my question is different.
I believe this would do the trick:
public List<ISomeInterface> GetList()
{
return someList.Cast<ISomeInterface>().ToList();
}
You could also do:
public List<ISomeInterface> GetList()
{
return someList.OfType<ISomeInterface>().ToList();
}
The difference is that the first option will do a hard cast, which means that if one of the elements does not implement ISomeInterface an exception will be thrown. The second version will only return instances that implement ISomeInterface and will just skip over instances that don't.
In your example, you can safely use the Cast option as you are guaranteed that all instances implement ISomeInterface.
You can use OfType<T>
public class GenericsTest<T> where T : ISomeInterface
{
private List<T> someList = new List<T>();
public List<ISomeInterface> GetList()
{
return someList.OfType<ISomeInterface>().ToList();
}
}
In C#, generic variance works differently than in Java. If you want to take advantage of it, you need to work with an interface (or delegate) that's variant. Such interfaces include IEnumerable<T> and IReadOnlyList<T> (new in .Net 4.5), but not IList<T>, because that wouldn't be type-safe.
That means you can do something like this:
public class GenericsTest<T> where T: ISomeInterface
{
private List<T> someList = new List<T>();
public IEnumerable<ISomeInterface> GetList()
{
return (IEnumerable<ISomeInterface>)someList;
}
}
here is the problem. lets pretend that this code would compile:
class foo: ISomeInterface {}
class bar: ISomeInterface {}
GenericsTest<foo> testobject = GenericsTest<foo>();
List<ISomeinterface> alist = testobject.GetList();
Internally testobject really has a list of foo but by allowing us to cast to a List<ISomeinterface> there is no way for a caller to know that bad things are going to happen if we try to insert a bar into the list. This is the reason that it isn't allowed and cant easily be allowed.
The way to solve it is to either:
Use a List<ISomeInterface> internally (if the collection becoming heterogeneous is OK)
Create a copy of the list with the desired type if the list being read only is OK. If you need to able to mutate the list in some cases you can add type safe methods on the GenericTest class to accomplish that.
One major weakness in Java and .NET is that there is no distinction made between mutable-type references which are used to encapsulate the identity of a mutable object, from those which are used to encapsulate its state. In particular, if code calls getList and then attempts to modify the returned list, it's not clear whether such an attempt should modify the list which is held by GenericsTest<T>, or whether it should simply modify a copy of the list which was created by the method (leaving the original list alone). It's also unclear whether the list returned by getList should be affected by any future changes which are made to the set of items held by the GenericsList<T>.
If your goal is to allow a caller to have a new list which is populated with the items in the original list, but which it can manipulate as it sees fit, I would suggest that you either use an AsList method or else define an interface
interface ICopyableToNewList<out T> {
// List<T> ToList(); // Can't be an actual interace member--must use extension method
int Count {get;}
}
implement a ToList() extension method which acts on that interface:
public static List<T> ToList<T>(this ICopyableToNewList<T> src)
and have your class implement ICopyableToNewList<T>. Such a declaration will allow code to get a new list of any type which is a supertype of T by casting the GenericTest<T> to ICopyableToNewList<desiredType>.

ienumerable vs list<T>

It is said that IEnumerable is used in a custom collection. One of the uses is the foreach loop used to traverse through the custom collection.
However my question is that instead of making a custom collection that first implements IEnumerable and then constructing another class to implement IEnumerator to store a group of custom objects, why can't we just use list<your_customer_object>.
Thanks in advance for help.
Because you might want to implement a different data structure. IEnumerable abstracts the concept of sequence, while a List has the concept of index, adding/removing items and its own, data structure.
As an example of different structure, here's a class which allows you to enter an infinite foreach loop.
public class InfiniteSequence : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new InfiniteEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
class InfiniteEnumerator : IEnumerator<int>
{
public void Dispose()
{
throw new NotImplementedException();
}
public bool MoveNext()
{
Current++;
return true;
}
public void Reset()
{
Current = 0;
}
public int Current { get; private set; }
object IEnumerator.Current
{
get { return Current; }
}
}
}
Of course you can use List<T>.
If List<T> fits your needs, then use it and don't create a new class that inherits from IEnumerable<T>.
You would provide your own implementation of IEnumerable<T> when List<T> isn't right for your needs. The canonical example of this is when you want to support lazy evaluation of your collection, perhaps with a method that uses yield return.
As #ken2k said, you can just List<T> and you will got a generic version of List with your T type. But if you want to hide this implementation and customize some operations that List<T> or include new features, you can inherits from the List and implement your own methods. For sample:
public class CustomerCollection : List<Customer> // at this time, you have all methods from List such as Add, Remove, [index] etc...
{
public double AverageAge()
{
return this.Average(customer => customer.Age)
}
// other methods...
}
IEnumeralbe is the most abstraction of collections in .Net Framework, you can just interate in this abstraction.
You can just use List<T> or any other of the generic collection types. After all List<T> implements IEnumerable<T>.
Do you have a particular edge case that you need to cover with a bespoke collection?
Of course you can define your members as List<T>, that however binds the customer of your class to a specific implementation. If you define the member as IEnumerable<T> (assuming that the consumers will only want to enumerate your collection) than you can change the implementation to a different collection type that implements the interface without breaking the contract. You if you change it from List<T> to SortedSet<T> to implement order your consumers are not affected.
It's basically the advantage of coding against interfaces rather than concrete types.
You can use a different interface, ie. ICollection<T> if your consumers want more than just enumerate.
If it doesn't do anything else, go ahead. Specialized collections are for collections that need to do... special... things.
(For example, a ListViewItemCollection would have to notify its parent ListView when updated, so it needs to implement IList(T), and therefore IEnumerable(T). If you had a custom collection, it might inherit from that. Inheriting only from IEnumerable(T) makes sense only when your collection can be enumerated, but not indexed.)
You Can.
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
I think the source of confusion here is the difference between a "custom collection" and a "collection of custom class instances". Of these two, your List<CustomObject> is the latter case - you are only reusing a collection created by someone else and taking advantage of generics to keep the item type info, that's all. Truly custom collection would probably implement IEnumerable<T>, but you will rarely (if ever) need it.
So in this case you not only can, but probably also should use List<CustomObject>

When should you use IEnumerable and GetEnumerator?

In many of our projects I have seen a few custom collection / or container classes that hold a some sort of generic collection, e.g. a List(of T) class.
They usually have a GetXXX method that returns a IEnumerable of whatever type the custom collection class uses so the internal collection can be iterated around using a foreach loop.
e.g.
public IEnumerable<UploadState> GetStates
{
get
{
return new List<UploadState>(m_states);
}
}
My question is that should these classes instead implement the IEnumerable interface, and call GetEnumerator on the List itself.
Is there a preferred way, or is it up to the developer?
If your class is a custom collection class then yes, it should implement IEnumerable<T>. In this case a public property for the inner list would be redundant. Imagine a simple class:
public class People : IEnumerable<Person>
{
List<Person> persons = new List<Person>();
public IEnumerator<Person> GetEnumerator()
{
return persons.GetEnumerator();
}
}
But if your class cannot act like a collection then provide a public IEnumerable property for its elements:
public class Flight
{
List<Person> passengers = new List<Person>();
public IEnumerable<Person> Passengers
{
get { return passengers; }
}
}
Anyway, it's always up to the developer to choose the right design.
I would do it that way:
public IEnumerable<UploadState> GetStates
{
get
{
foreach (var state in m_states) {
yield return state;
}
}
}
It is cleaner, your users don't get a list where they shouldn't (they could cast it to a List<T>after all) and you don't need to create a List<T>object.
EDIT: Misunderstood the question. I think if the class is meant to be a collection, it should implement IEnumerable<T>.
Consider that in your code example a new list created. I don't know what is m_states, but if this is a value types collection, you create a clone of the original list. In this way the returning list can be manipulated form the caller Add/Remove/Update elements. without affectiing original data.
If m_states are reference types, this still creates a new list which can be again manipulated by the caller Add/Remove/ No update elements (it's a reference!) without affecting original data.
What about IEnumerable<T>, its just a way to make a returning type generic, and not make strong coupling to List<T> type.
I think if your newly implemented class just behaves the sameway as a list does, there is no need to implement it. If you need some kind of custom logic, it depends on what you want to do; you can inherit list or you can implement IEnumerable. It just depends what is to be achieved.
You might want to check this:
http://www.codeproject.com/Articles/4074/Using-IEnumerator-and-IEnumerable-in-the-NET-Frame
I didn't read fully it yet, but I think this answers your question.
You should be deriving your custom collection classes based on one of the classes in System.Collections.ObjectModel namespace. They already contain implementations of IEnumerable<T> and the non generic IEnumerable interfaces.

Why use IList or List?

I know there has been a lot of posts on this but it still confuses me why should you pass in an interface like IList and return an interface like IList back instead of the concrete list.
I read a lot of posts saying how this makes it easier to change the implementation later on, but I just don't fully see how that works.
Say if I have this method
public class SomeClass
{
public bool IsChecked { get; set; }
}
public void LogAllChecked(IList<SomeClass> someClasses)
{
foreach (var s in someClasses)
{
if (s.IsChecked)
{
// log
}
}
}
I am not sure how using IList will help me out in the future.
How about if I am already in the method? Should I still be using IList?
public void LogAllChecked(IList<SomeClass> someClasses)
{
//why not List<string> myStrings = new List<string>()
IList<string> myStrings = new List<string>();
foreach (var s in someClasses)
{
if (s.IsChecked)
{
myStrings.Add(s.IsChecked.ToString());
}
}
}
What do I get for using IList now?
public IList<int> onlySomeInts(IList<int> myInts)
{
IList<int> store = new List<int>();
foreach (var i in myInts)
{
if (i % 2 == 0)
{
store.Add(i);
}
}
return store;
}
How about now? Is there some new implementation of a list of int's that I will need to change out?
Basically, I need to see some actual code examples of how using IList would have solved some problem over just taking List into everything.
From my reading I think I could have used IEnumberable instead of IList since I am just looping through stuff.
Edit
So I have been playing around with some of my methods on how to do this. I am still not sure about the return type(if I should make it more concrete or an interface).
public class CardFrmVm
{
public IList<TravelFeaturesVm> TravelFeaturesVm { get; set; }
public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; }
public CardFrmVm()
{
WarrantyFeaturesVm = new List<WarrantyFeaturesVm>();
TravelFeaturesVm = new List<TravelFeaturesVm>();
}
}
public class WarrantyFeaturesVm : AvailableFeatureVm
{
}
public class TravelFeaturesVm : AvailableFeatureVm
{
}
public class AvailableFeatureVm
{
public Guid FeatureId { get; set; }
public bool HasFeature { get; set; }
public string Name { get; set; }
}
private IList<AvailableFeature> FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm)
{
List<AvailableFeature> availableFeatures = new List<AvailableFeature>();
foreach (var f in avaliableFeaturesVm)
{
if (f.HasFeature)
{
// nhibernate call to Load<>()
AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
availableFeatures.Add(availableFeature);
}
}
return availableFeatures;
}
Now I am returning IList for the simple fact that I will then add this to my domain model what has a property like this:
public virtual IList<AvailableFeature> AvailableFeatures { get; set; }
The above is an IList itself as this is what seems to be the standard to use with nhibernate. Otherwise I might have returned IEnumberable back but not sure. Still, I can't figure out what the user would 100% need(that's where returning a concrete has an advantage over).
Edit 2
I was also thinking what happens if I want to do pass by reference in my method?
private void FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm, IList<AvailableFeature> toFill)
{
foreach (var f in avaliableFeaturesVm)
{
if (f.HasFeature)
{
// nhibernate call to Load<>()
AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId);
toFill.Add(availableFeature);
}
}
}
would I run into problems with this? Since could they not pass in an array(that has a fixed size)? Would it be better maybe for a concrete List?
There are three questions here: what type should I use for a formal parameter? What should I use for a local variable? and what should I use for a return type?
Formal parameters:
The principle here is do not ask for more than you need. IEnumerable<T> communicates "I need to get the elements of this sequence from beginning to end". IList<T> communicates "I need to get and set the elements of this sequence in arbitrary order". List<T> communicates "I need to get and set the elements of this sequence in arbitrary order and I only accept lists; I do not accept arrays."
By asking for more than you need, you (1) make the caller do unnecessary work to satisfy your unnecessary demands, and (2) communicate falsehoods to the reader. Ask only for what you're going to use. That way if the caller has a sequence, they don't need to call ToList on it to satisfy your demand.
Local variables:
Use whatever you want. It's your method. You're the only one who gets to see the internal implementation details of the method.
Return type:
Same principle as before, reversed. Offer the bare minimum that your caller requires. If the caller only requires the ability to enumerate the sequence, only give them an IEnumerable<T>.
The most practical reason I've ever seen was given by Jeffrey Richter in CLR via C#.
The pattern is to take the basest class or interface possible for your arguments and return the most specific class or interface possible for your return types. This gives your callers the most flexibility in passing in types to your methods and the most opportunities to cast/reuse the return values.
For example, the following method
public void PrintTypes(IEnumerable items)
{
foreach(var item in items)
Console.WriteLine(item.GetType().FullName);
}
allows the method to be called passing in any type that can be cast to an enumerable. If you were more specific
public void PrintTypes(List items)
then, say, if you had an array and wished to print their type names to the console, you would first have to create a new List and fill it with your types. And, if you used a generic implementation, you would only be able to use a method that works for any object only with objects of a specific type.
When talking about return types, the more specific you are, the more flexible callers can be with it.
public List<string> GetNames()
you can use this return type to iterate the names
foreach(var name in GetNames())
or you can index directly into the collection
Console.WriteLine(GetNames()[0])
Whereas, if you were getting back a less specific type
public IEnumerable GetNames()
you would have to massage the return type to get the first value
Console.WriteLine(GetNames().OfType<string>().First());
IEnumerable<T> allows you to iterate through a collection. ICollection<T> builds on this and also allows for adding and removing items. IList<T> also allows for accessing and modifying them at a specific index. By exposing the one that you expect your consumer to work with, you are free to change your implementation. List<T> happens to implement all three of those interfaces.
If you expose your property as a List<T> or even an IList<T> when all you want your consumer to have is the ability to iterate through the collection. Then they could come to depend on the fact that they can modify the list. Then later if you decide to convert the actual data store from a List<T> to a Dictionary<T,U> and expose the dictionary keys as the actual value for the property (I have had to do exactly this before). Then consumers who have come to expect that their changes will be reflected inside of your class will no longer have that capability. That's a big problem! If you expose the List<T> as an IEnumerable<T> you can comfortably predict that your collection is not being modified externally. That is one of the powers of exposing List<T> as any of the above interfaces.
This level of abstraction goes the other direction when it belongs to method parameters. When you pass your list to a method that accepts IEnumerable<T> you can be sure that your list is not going to be modified. When you are the person implementing the method and you say you accept an IEnumerable<T> because all you need to do is iterate through that list. Then the person calling the method is free to call it with any data type that is enumerable. This allows your code to be used in unexpected, but perfectly valid ways.
From this it follows that your method implementation can represent its local variables however you wish. The implementation details are not exposed. Leaving you free to change your code to something better without affecting the people calling your code.
You cannot predict the future. Assuming that a property's type will always be beneficial as a List<T> is immediately limiting your ability to adapt to unforeseen expectations of your code. Yes, you may never change that data type from a List<T> but you can be sure that if you have to. Your code is ready for it.
Short Answer:
You pass the interface so that no matter what concrete implementation of that interface you use, your code will support it.
If you use a concrete implementation of list, another implementation of the same list will not be supported by your code.
Read a bit on inheritance and polymorphism.
Here's an example: I had a project once where our lists got very large, and resulting fragmentation of the large object heap was hurting performance. We replaced List with LinkedList. LinkedList does not contain an array, so all of a sudden, we had almost no use of the large object heap.
Mostly, we used the lists as IEnumerable<T>, anyway, so there was no further change needed. (And yes, I would recommend declaring references as IEnumerable if all you're doing is enumerating them.) In a couple of places, we needed the list indexer, so we wrote an inefficient IList<T> wrapper around the linked lists. We needed the list indexer infrequently, so the inefficiency was not a problem. If it had been, we could have provided some other implementation of IList, perhaps as a collection of small-enough arrays, that would have been more efficiently indexable while also avoiding large objects.
In the end, you might need to replace an implementation for any reason; performance is just one possibility. Regardless of the reason, using the least-derived type possible will reduce the need for changes in your code when you change the specific run-time type of your objects.
Inside the method, you should use var, instead of IList or List. When your data source changes to come from a method instead, your onlySomeInts method will survive.
The reason to use IList instead of List as parameters, is because many things implement IList (List and [], as two examples), but only one thing implements List. It's more flexible to code to the interface.
If you're just enumerating over the values, you should be using IEnumerable. Every type of datatype that can hold more than one value implements IEnumerable (or should) and makes your method hugely flexible.
Using IList instead of List makes writing unit tests significantly easier. It allows you to use a 'Mocking' library to pass and return data.
The other general reason for using interfaces is to expose the minimum amount of knowledge necessary to the user of an object.
Consider the (contrived) case where I have a data object that implements IList.
public class MyDataObject : IList<int>
{
public void Method1()
{
...
}
// etc
}
Your functions above only care about being able to iterate over a list. Ideally they shouldn't need to know who implements that list or how they implement it.
In your example, IEnumerable is a better choice as you thought.
It is always a good idea to reduce the dependencies between your code as much as possible.
Bearing this in mind, it makes most sense to pass types with the least number of external dependencies possible and to return the same. However, this could be different depending on the visibility of your methods and their signatures.
If your methods form part of an interface, the methods will need to be defined using types available to that interface. Concrete types will probably not be available to interfaces, so they would have to return non-concrete types. You would want to do this if you were creating a framework, for example.
However, if you are not writing a framework, it may be advantageous to pass parameter with the weakest possible types (i.e. base classes, interfaces, or even delegates) and return concrete types. That gives the caller the ability to do as much as possible with the returned object, even if it is cast as an interface. However, this makes the method more fragile, as any change to the returned object type may break the calling code. In practice though, that generally isn't a major problem.
You accept an Interface as a parameter for a method because that allows the caller to submit different concrete types as arguments. Given your example method LogAllChecked, the parameter someClasses could be of various types, and for the person writing the method, all might be equivalent (i.e. you'd write the exact same code regardless of the type of the parameter). But for the person calling the method, it can make a huge difference -- if they have an array and you're asking for a list, they have to change the array to a list or v.v. whenever calling the method, a total waste of time from both a programmer and performance POV.
Whether you return an Interface or a concrete type depends upon what you want to let your callers do with the object you created -- this is an API design decision, and there's no hard and fast rule. You have to weigh their ability to make full use of the object against their ability to easily use a portion of the objects functionality (and of course whether you WANT them to be making full use of the object). For instance, if you return an IEnumerable, then you are limiting them to iterating -- they can't add or remove items from your object, they can only act against the objects. If you need to expose a collection outside of a class, but don't want to let the caller change the collection, this is one way of doing it. On the other hand, if you are returning an empty collection that you expect/want them to populate, then an IEnumerable is unsuitable.
Here's my answer in this .NET 4.5+ world.
Use IList<T> and IReadonlyList<T>,
instead of List<T>, because ReadonlyList<T> doesn't exist.
IList<T> looks so consistent with IReadonlyList<T>
Use IEnumerable<T> for minimum exposure (property) or requirement (parameter) if foreach is the only way to use it.
Use IReadonlyList<T> if you also need to expose/use Count and [] indexer.
Use IList<T> if you also allow callers to add/update/delete elements
because List<T> implements IReadonlyList<T>, it doesn't need any explicit casting.
An example class:
// manipulate the list within the class
private List<int> _numbers;
// callers can add/update/remove elements, but cannot reassign a new list to this property
public IList<int> Numbers { get { return _numbers; } }
// callers can use: .Count and .ReadonlyNumbers[idx], but cannot add/update/remove elements
public IReadOnlyList<int> ReadonlyNumbers { get { return _numbers; } }

Casting generic container of type to container of inherited type?

If I have two classes:
public class A { }
public class B : A { }
and I create a generic container and a function that takes it:
public void Foo(List<A> lst) { ... }
I get an invalid conversion if I attempt casting a List<B> to a List<A>, and instead have to pass it like so:
var derivedList = new List<B>();
Foo(new List<A>(derivedList));
Is there some way to pass a List<B> to this function without the overhead of allocating a brand new list, or does C# not support converting from a generic container of a derived type to its base type?
A List<B> simply isn't a List<A> - after all, you can add a plain A to a List<A>, but not to a List<B>.
If you're using C# 4 and .NET 4 and your Foo method only really needs to iterate over the list, then change the method to:
public void Foo(IEnumerable<A> lst) { ... }
In .NET 4, IEnumerable<T> is covariant in T, which allows a conversion from IEnumerable<B> (including a List<B>) to IEnumerable<A>. This is safe because values only ever flow "out" of IEnumerable<A>.
For a much more detailed look at this, you can watch the video of the session I gave at NDC 2010 as part of the torrent of NDC 2010 videos.
This is not possible. C# doesn't support co / contra variance on concrete types such as List<T>. It does support it on interfaces though so if you switch Foo to the following signature you can avoid an allocation
public void Foo(IEnumerable<A> enumerable) { ...
If you wish to pass list-like things to routines which are going to read them but not write them, it would be possible to define a generic covariant IReadableList<out T> interface, so that an IReadableList<Cat> could be passed to a routine expecting an IReadableList<Animal>. Unfortunately, common existing IList<T> implementations don't implement any such thing, and so the only way to implement one would be to implement a wrapper class (which could accept an IList as a parameter), but it probably wouldn't be too hard. Such a class should also implement non-generic IList, also as read-only, to allow code to evaluate Count without having to know the type of the items in the list.
Note that an object's implementation of IReadableList<T> should not be regarded as any promise of immutability. It would be perfectly reasonable to have a read-write list or wrapper class implement IReadableList<T>, since a read-write list is readable. It's not possible to use an IReadableList<T> to modify a list without casting it to something else, but there's no guarantee a list passed as IReadableList<T> can't be modified some other way, such as by casting it to something else, or by using a reference stored elsewhere.

Categories

Resources