Why doesn't INotifyCollectionChanged extend IList? - c#

I've ran into the situation a couple of times where I want to observe a collection through the INotifyCollectionChanged interface, but also want to be able to access any of the collection's elements. The INotifyCollectionChanged interface doesn't provide any way to access the elements, except for those that are involved in the change event (which (usually) are contained in the NotifyCollectionChangedEventArgs).
Now here's my thinking:
We know that whatever implements INotifyCollectionChanged is a collection (d'uh).
Since the NotifyPropertyChangedEventArgs contains indices indication the location of the change, we know that the elements can be accessed by index.
A collection that can be accessed by index is a list, so it seems to be that it would make sense to require that any INotifyCollectionChanged implementor also implements IList. This could easily be done by letting INotifyCollectionChanged extend IList.
Does anyone know why this is not the case?

I think you need to look up the SOLID software design principles, specifically the Liskov Substitution Principle.
You asked why the INotifyCollectionChanged interface does not also extend the IList interface. Let me answer it with a counter question using the Liskov Subsitution Principle:
Can I say an INotifyCollectionChanged is an IList?
No I don't think so, for the following reasons:
INotifyCollectionChanged conveys the meaning that classes implementing this interface need to notify their users if its underlying collection was changed, whether that underlying collection is an IList or ICollection, or even IEnumerable, we do not know. It's different concept of an IList interface, which is simply an ICollection with an exposed indexer
You mentioned NotifyPropertyChangedEventArgs (which I believe you meant NotifyCollectionChangedEventArgs instead) exposes properties of the indices indicating at what position the collection is changed. However this does not mean these properties necessarily expose the items through the indexers of IList. It can be an arbitrary number, a magic constant, whatever. It is up to the implementing class to decide how to expose the indices.
To demonstrate this, please take a look at my custom class that implements INotifyCollectionChanged:
public class MyCustomCollection : INotifyCollectionChanged
{
// This is what I meant by the "underlying collection", can be replaced with
// ICollection<int> and it will still work, or even IEnumerable<int> but with some
// code change to store the elements in an array
private readonly IList<int> _ints;
public MyCustomCollection()
{
_ints = new List<int>();
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public void AddInt(int i)
{
_ints.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Move,
(IList)_ints,
_ints.Count,
_ints.Count - 1));
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
var handler = CollectionChanged;
if (handler != null)
{
handler(this, e);
}
}
}
Hope this answer your question.

I don’t know why, but I see reasons for that decision (without any knowledge of the decision – it’s just my opinion):
Implementing INotifyCollectionChanged this way follows the principle of role-interfaces (the change notification is described rather than the object) Please see #rexcfnghk post for that!
Only the changed elements in the EventArgs are represented as an IList<T>, that does not mean that the collection itself needs to be a list
To conclude, they made a decision to make the default collection with change notification a Collection<T> using an interface that allows that was required.

Related

Is returning IList<T> worse than returning T[] or List<T>?

The answers to questions like this: List<T> or IList<T> always seem to agree that returning an interface is better than returning a concrete implementation of a collection. But I'm struggling with this. Instantiating an interface is impossible, so if your method is returning an interface, it's actually still returning a specific implementation. I was experimenting a bit with this by writing 2 small methods:
public static IList<int> ExposeArrayIList()
{
return new[] { 1, 2, 3 };
}
public static IList<int> ExposeListIList()
{
return new List<int> { 1, 2, 3 };
}
And use them in my test program:
static void Main(string[] args)
{
IList<int> arrayIList = ExposeArrayIList();
IList<int> listIList = ExposeListIList();
//Will give a runtime error
arrayIList.Add(10);
//Runs perfectly
listIList.Add(10);
}
In both cases when I try to add a new value, my compiler gives me no errors, but obviously the method which exposes my array as an IList<T> gives a runtime error when I try to add something to it.
So people who don't know what's happening in my method, and have to add values to it, are forced to first copy my IList to a List to be able to add values without risking errors. Of course they can do a typecheck to see if they're dealing with a List or an Array, but if they don't do that, and they want to add items to the collection they have no other choice to copy the IList to a List, even if it already is a List. Should an array never be exposed as IList?
Another concern of mine is based upon the accepted answer of the linked question (emphasis mine):
If you are exposing your class through a library that others will use, you generally want to expose it via interfaces rather than concrete implementations. This will help if you decide to change the implementation of your class later to use a different concrete class. In that case the users of your library won't need to update their code since the interface doesn't change.
If you are just using it internally, you may not care so much, and using List may be ok.
Imagine someone actually used my IList<T> they got from my ExposeListIlist() method just like that to add/remove values. Everything works fine. But now like the answer suggests, because returning an interface is more flexible I return an array instead of a List (no problem on my side!), then they're in for a treat...
TLDR:
1) Exposing an interface causes unnecessary casts? Does that not matter?
2) Sometimes if users of the library don't use a cast, their code can break when you change your method, even though the method remains perfectly fine.
I am probably overthinking this, but I don't get the general consensus that returning an interface is to be preferred over returning an implementation.
Maybe this is not directly answering your question, but in .NET 4.5+, I prefer to follow these rules when designing public or protected APIs:
do return IEnumerable<T>, if only enumeration is available;
do return IReadOnlyCollection<T> if both enumeration and items count are available;
do return IReadOnlyList<T>, if enumeration, items count and indexed access are available;
do return ICollection<T> if enumeration, items count and modification are available;
do return IList<T>, if enumeration, items count, indexed access and modification are available.
Last two options assume, that method must not return array as IList<T> implementation.
No, because the consumer should know what exactly IList is:
IList is a descendant of the ICollection interface and is the base
interface of all non-generic lists. IList implementations fall into
three categories: read-only, fixed-size, and variable-size. A
read-only IList cannot be modified. A fixed-size IList does not allow
the addition or removal of elements, but it allows the modification of
existing elements. A variable-size IList allows the addition, removal,
and modification of elements.
You can check for IList.IsFixedSize and IList.IsReadOnly and do what you want with it.
I think IList is an example of a fat interface and it should have been split into multiple smaller interfaces and it also violates Liskov substitution principle when you return an array as an IList.
Read more if you want to make decision about returning interface
UPDATE
Digging more and I found that IList<T> does not implement IList and IsReadOnly is accessible through base interface ICollection<T> but there is no IsFixedSize for IList<T>. Read more about why generic IList<> does not inherit non-generic IList?
As with all "interface versus implementation" question, you'll have to realise what exposing a public member means: it defines the public API of this class.
If you expose a List<T> as a member (field, property, method, ...), you tell the consumer of that member: the type obtained by accessing this method is a List<T>, or something derived of that.
Now if you expose an interface, you hide the "implementation detail" of your class using a concrete type. Of course you can't instantiate IList<T>, but you can use an Collection<T>, List<T>, derivations thereof or your own type implementing IList<T>.
The actual question is "Why does Array implement IList<T>", or "Why has the IList<T> interface so many members".
It also depends on what you want the consumers of that member to do. If you actually return an internal member through your Expose... member, you'll want to return a new List<T>(internalMember) anyway, as otherwise the consumer can try and cast them to IList<T> and modify your internal member through that.
If you just expect consumers to iterate the results, expose IEnumerable<T> or IReadOnlyCollection<T> instead.
Be careful with blanket quotes that are taken out of context.
Returning an interface is better than returning a concrete implementation
This quote only makes sense if it's used in the context of the SOLID principles. There are 5 principles but for the purposes of this discussion we'll just talk about the last 3.
Dependency inversion principle
one should “Depend upon Abstractions. Do not depend upon concretions.”
In my opinion, this principle is the most difficult to understand. But if you look at the quote carefully it looks a lot like your original quote.
Depend on interfaces (abstractions). Do no depend on concrete implementations (concretions).
This is still a little confusing but if we start applying the other principles together it starts to make a lot more sense.
Liskov substitution principle
“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.”
As you pointed out, returning an Array is clearly different behavior to returning a List<T> even though they both implement IList<T>. This is most certainly a violation of LSP.
The important thing to realize is that interfaces are about the consumer. If you're returning an interface, you've created a contract that any methods or properties on that interface can be used without changing the behavior of the program.
Interface segregation principle
“many client-specific interfaces are better than one general-purpose interface.”
If you're returning an interface, you should return the most client specific interface your implementation supports. In other words, if you're not expecting the client to call the Add method you shouldn't return an interface with an Add method on it.
Unfortunately, the interfaces in the .NET framework (particularly the early versions) are not always ideal client specific interfaces. Although as #Dennis pointed out in his answer, there are a lot more choices in .NET 4.5+.
Returning an interface is not necessarily better than returning a concrete implementation of a collection. You should always have a good reason to use an interface instead of a concrete type. In your example it seems pointless to do so.
Valid reasons to use an interface could be:
You do not know what the implementation of the methods returning the interface will look like and there may be many, developed over time. It may be other people writing them, from other companies. So you just want to agree on the bare necessities and leave it up to them how to implement the functionality.
You want to expose some common functionality independent from your class hierarchy in a type-safe way. Objects of different base types that should offer the same methods would implement your interface.
One could argue that 1 and 2 are basically the same reason. They are two different scenarios that ultimately lead to the same need.
"It's a contract". If the contract is with yourself and your application is closed in both functionality and time, there is often no point in using an interface.

IEnumerable vs IReadonlyCollection vs ReadonlyCollection for exposing a list member

I have spent quite a few hours pondering the subject of exposing list members. In a similar question to mine, Jon Skeet gave an excellent answer. Please feel free to have a look.
ReadOnlyCollection or IEnumerable for exposing member collections?
I am usually quite paranoid to exposing lists, especially if you are developing an API.
I have always used IEnumerable for exposing lists, as it is quite safe, and it gives that much flexibility. Let me use an example here:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IEnumerable<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
Anyone who codes against an IEnumerable is quite safe here. If I later decide to use an ordered list or something, none of their code breaks and it is still nice. The downside of this is IEnumerable can be cast back to a list outside of this class.
For this reason, a lot of developers use ReadOnlyCollection for exposing a member. This is quite safe since it can never be cast back to a list. For me I prefer IEnumerable since it provides more flexibility, should I ever want to implement something different than a list.
I have come up with a new idea I like better. Using IReadOnlyCollection:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return new ReadOnlyCollection<WorkItem>(this.workItems);
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
I feel this retains some of the flexibility of IEnumerable and is encapsulated quite nicely.
I posted this question to get some input on my idea. Do you prefer this solution to IEnumerable? Do you think it is better to use a concrete return value of ReadOnlyCollection? This is quite a debate and I want to try and see what are the advantages/disadvantages that we all can come up with.
EDIT
First of all thank you all for contributing so much to the discussion here. I have certainly learned a ton from each and every one and would like to thank you sincerely.
I am adding some extra scenarios and info.
There are some common pitfalls with IReadOnlyCollection and IEnumerable.
Consider the example below:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
The above example can be casted back to a list and mutated, even though the interface is readonly. The interface, despite it's namesake does not guarantee immutability. It is up to you to provide an immutable solution, therefore you should return a new ReadOnlyCollection. By creating a new list (a copy essentially), the state of your object is safe and sound.
Richiban says it best in his comment: a interface only guarantees what something can do, not what it cannot do.
See below for an example:
public IEnumerable<WorkItem> WorkItems
{
get
{
return new List<WorkItem>(this.workItems);
}
}
The above can be casted and mutated, but your object is still immutable.
Another outside the box statement would be collection classes. Consider the following:
public class Bar : IEnumerable<string>
{
private List<string> foo;
public Bar()
{
this.foo = new List<string> { "123", "456" };
}
public IEnumerator<string> GetEnumerator()
{
return this.foo.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
The class above can have methods for mutating foo the way you want it to be, but your object can never be casted to a list of any sort and mutated.
Carsten Führmann makes a fantastic point about yield return statements in IEnumerables.
One important aspect seems to be missing from the answers so far:
When an IEnumerable<T> is returned to the caller, they must consider the possibility that the returned object is a "lazy stream", e.g. a collection built with "yield return". That is, the performance penalty for producing the elements of the IEnumerable<T> may have to be paid by the caller, for each use of the IEnumerable. (The productivity tool "Resharper" actually points this out as a code smell.)
By contrast, an IReadOnlyCollection<T> signals to the caller that there will be no lazy evaluation. (The Count property, as opposed to the Count extension method of IEnumerable<T> (which is inherited by IReadOnlyCollection<T> so it has the method as well), signals non-lazyness. And so does the fact that there seem to be no lazy implementations of IReadOnlyCollection.)
This is also valid for input parameters, as requesting an IReadOnlyCollection<T> instead of IEnumerable<T> signals that the method needs to iterate several times over the collection. Sure the method could create its own list from the IEnumerable<T> and iterate over that, but as the caller may already have a loaded collection at hand it would make sense to take advantage of it whenever possible. If the caller only has an IEnumerable<T> at hand, he only needs to add .ToArray() or .ToList() to the parameter.
What IReadOnlyCollection does not do is prevent the caller to cast to some other collection type. For such protection, one would have to use the class ReadOnlyCollection<T>.
In summary, the only thing IReadOnlyCollection<T> does relative to IEnumerable<T> is add a Count property and thus signal that no lazyness is involved.
Talking about class libraries, I think IReadOnly* is really useful, and I think you're doing it right :)
It's all about immutable collection... Before there were just immutables and to enlarge arrays was a huge task, so .net decided to include in the framework something different, mutable collection, that implement the ugly stuff for you, but IMHO they didn't give you a proper direction for immutable that are extremely useful, especially in a high concurrency scenario where sharing mutable stuff is always a PITA.
If you check other today languages, such as objective-c, you will see that in fact the rules are completely inverted! They quite always exchange immutable collection between different classes, in other words the interface expose just immutable, and internally they use mutable collection (yes, they have it of course), instead they expose proper methods if they want let the outsiders change the collection (if the class is a stateful class).
So this little experience that I've got with other languages pushes me to think that .net list are so powerful, but the immutable collection were there for some reason :)
In this case is not a matter of helping the caller of an interface, to avoid him to change all the code if you're changing internal implementation, like it is with IList vs List, but with IReadOnly* you're protecting yourself, your class, to being used in not a proper way, to avoid useless protection code, code that sometimes you couldn't also write (in the past in some piece of code I had to return a clone of the complete list to avoid this problem).
My take on concerns of casting and IReadOnly* contracts, and 'proper' usages of such.
If some code is being “clever” enough to perform an explicit cast and break the interface contract, then it is also “clever” enough to use reflection or otherwise do nefarious things such as access the underlying List of a ReadOnlyCollection wrapper object. I don’t program against such “clever” programmers.
The only thing that I guarantee is that after said IReadOnly*-interface objects are exposed, then my code will not violate that contract and will not modified the returned collection object.
This means that I write code that returns List-as-IReadOnly*, eg., and rarely opt for an actual read-only concrete type or wrapper. Using IEnumerable.ToList is sufficient to return an IReadOnly[List|Collection] - calling List.AsReadOnly adds little value against “clever” programmers who can still access the underlying list that the ReadOnlyCollection wraps.
In all cases, I guarantee that the concrete types of IReadOnly* return values are eager. If I ever write a method that returns an IEnumerable, it is specifically because the contract of the method is that which “supports streaming” fsvo.
As far as IReadOnlyList and IReadOnlyCollection, I use the former when there is 'an' implied stable ordering established that is meaningful to index, regardless of purposeful sorting. For example, arrays and Lists can be returned as an IReadOnlyList while a HashSet would better be returned as an IReadOnlyCollection. The caller can always assign the I[ReadOnly]List to an I[ReadOnly]Collection as desired: this choice is about the contract exposed and not what a programmer, “clever” or otherwise, will do.
It seems that you can just return an appropriate interface:
...
private readonly List<WorkItem> workItems = new List<WorkItem>();
// Usually, there's no need the property to be virtual
public virtual IReadOnlyList<WorkItem> WorkItems {
get {
return workItems;
}
}
...
Since workItems field is in fact List<T> so the natural idea IMHO is to expose the most wide interface which is IReadOnlyList<T> in the case
!! IEnumerable vs IReadOnlyList !!
IEnumerable has been with us from the beginning of time. For many years, it was a de facto standard way to represent a read-only collection. Since .NET 4.5, however, there is another way to do that: IReadOnlyList.
Both collection interfaces are useful.
<>

C#: ObservableCollection - why no generic "CollectionChanged" event?

This is not so much a question, and more something that struck me as odd: the ObservableCollection class is generic, but the CollectionChanged event that it raises when changed to the collection occur is not. That means within the event handler, you have to cast all the objects in the NewItems/OldItems collections you get from the event args object to the proper item type yourself.
But shouldn't it have been simply possible to make that event generic? Something like
public virtual event NotifyCollectionChangedEventHandler<T> CollectionChanged;
with
public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs<T> e);
and then
public class NotifyCollectionChangedEventArgs<T> {
// ...
public IList<T> NewItems { get; }
public IList<T> OldItems { get; }
After all, the type parameter T is already determined by the declaration of the ObservableCollection in question, which means you should never be able to add any objects that are not of type T (or compatible to it) to the collection anyway. So all of this should be perfectly type safe, and save us the trouble of having to cast the objects inside the event handler into whatever type we know they should have anyway.
Is there a reason for not doing it this way that I am missing? I.e. is this a conscious design desicion, or just an oversight?
The INotifyCollectionChanged interface, along with INotifyPropertyChanged, were designed exclusively for use by the WPF framework. Since WPF is loosely typed, I'm guessing that generics weren't part of that design. I don't think INotifyCollectionChanged was designed to be consumed directly. Whereas, ObservableCollection<T> is designed to be consumed by C# code, which is strongly typed, therefore generics featured in the design.

Persistent collections and standard collection interfaces

I'm implementing a persistent collection - for the sake of argument, let's say it's a singly-linked list, of the style common in functional languages.
class MyList<T>
{
public T Head { get; }
public MyList<T> Tail { get; }
// other various stuff
// . . .
}
It seems natural to have this class implement ICollection<T>, since it can implement all the normal behavior one would expect of an ICollection<T>, at least in broad strokes. But there is a lot of mismatch between this class's behavior and ICollection<T>. For example, the signature of the Add() method
void Add(T item); // ICollection<T> version
assumes that the addition will be performed as a side-effect that mutates the collection. But this is a persistent data structure, so Add() should instead create a new list and return it.
MyList<T> Add(T item); // what we really want
It seems the best way to resolve this is to just create the version we want, and also generate a non-functional explicit implementation of the version defined in the interface.
void ICollection<T>.Add(T item) { throw new NotSupportedException(); }
public MyList<T> Add(T item) { return new MyList<T>(item, this); }
But I have a few concerns about that option:
Will this be confusing to users? I envision scenarios where someone is working with this class, and finds that calling Add() on it sometimes raises an exception, and sometimes runs but doesn't modify the list as would normally be expected for an ICollection, depending on the type information associated with the reference being used?
Following on (1), the implementation of ICollection<T>'s IsReadOnly should presumably return true. But that would seem to conflict with what is implied in other spots where Add() is being used with instances of the class.
Is (2) resolved in a non-confusing way by following the explicit implementation pattern again, with the new version returning false and the explicit implementation returning true? Or does this just make it even worse by falsely implying that MyList<T>'s Add() method is a mutator?
Or would it be better to forget trying to use the existing interface and just create a separate IPersistentCollection<T> interface that derives from IEnumerable<T> instead?
edit I changed the name of the class, and switched over to using ICollection. I wanted to focus on the object's behavior and how it relates to the interface. I just went with the cons list as a simple example. I appreciate the advice that if I were to implement a cons list I should try and come up with a less-confusing name and, should avoid implementing IList because that interface is intended for fast random access, but they are somewhat tangential issues.
What I intended to ask about is what others think about the tension between the semantics of read-only (or immutable) collections that are baked into the Framework, and persistent collections which implement equivalent behavior to what is described by the interface, only functionally rather than through mutating side effects.
Will implementing IList<T> be confusing?
Yes. Though there are situations in which an implementation of IList<T> throws -- say, when you are attempting to resize the list but its implementation is an array -- I would find it quite confusing to have an IList<T> that could be mutated in no way and did not have fast random access.
Should I implement a new IPersistentList<T>?
That depends on whether anyone will use it. Are consumers of your class likely to have a half-dozen different implementations of IPL<T> to choose from? I see no point in making an interface that is implemented by only one class; just use the class.
WPF's ItemsControl can get better performance if its ItemsSource is an IList<T> instead of an IEnumerable<T>.
But your persistent linked list will not have fast random access anyway.
It would make more sense to me to make a new IPersistentList<T> (or IImmutableList<T> since "persistent" sounds to me like the data is saved off somewhere.) interface since, really, it's different behavior than what is expected of an IList<T>. Classes that implement IList<T> should be mutable IMHO.
Oh, and of course, I'd avoid using the class name List<T> since it's already part of the framework.

How does ObservableCollection<T>.Add work?

I was trying to implement a specialized collection that works like ObservableCollection to encapsulate some more mechanisms in it, to do that i also let my collection inherit from Collection and i also implement the same interfaces.
I just do not get though how one actually implements the whole collection-changed-logic, for example Collection<T>.Add is not being overridden (it is not even marked as virtual), so how does the ObservableCollection fire the CollectionChanged event if items were added using that method?
To answer your specific question, Collection<T>.Add calls the InsertItem virtual method (after checking that the collection is not read-only). ObservableCollection<T> indeed overrides this method to do the insert and raise the relevant change notifications.
It does so by calling InsertItem which is overridden and can be seen upon decompilation
protected override void InsertItem(int index, T item)
{
this.CheckReentrancy();
base.InsertItem(index, item);
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
Remember, the key is not in overriding the base Collection methods, it's in the fact that you will be implementing the ICollection interface. And frankly, rather than inheriting from a Collection class, I would suggest instead creating an adapter class that takes a ICollection in the constructor and your methods will just delegate to the inner collection and raise the appropriate events.

Categories

Resources