Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Class library collections ObservableCollection<T> vs Collection<T>

I'm creating a class library that could be used in a number of situations ASP.NET, Console Apps, other class libraries and XAML targets like Silverlight or WPF.

Initially I decided to expose collections as IList. But then when writing samples using XAML I found that if I want to make it easy to bind to these collections I need to use ObservableCollection.

What are my options?

I could make the library expose ObservableCollection and force that upon users who have nothing to do with XAML. Is that a bad thing?

I could make my class generic allowing the caller to specify the collection type they want as long as it implements ICollection perhaps with default to Collection

I could make a set of classes one that uses ObservableCollection and one that does not say Foo and ObservableFoo.

I could implement INotifyCollectionChanged in my class but that seems silly when ObservableCollection does it for me.

Obviously I'm trying to keep the code clean and simple, but supporting data binding seems important.

Any suggestions?

Edit: Tried creating a Portable Class Library project using both alternatives.

In class Foo I have

    private readonly Collection<string> strings = new Collection<string>();

    public ReadOnlyCollection<string> Strings
    {
        get
        {
            return new ReadOnlyCollection<string>(this.strings);
        }
    }

In class ObservableFoo I have

    private readonly ObservableCollection<string> strings = new ObservableCollection<string>();

    public ReadOnlyObservableCollection<string> Strings
    {
        get
        {
            return new ReadOnlyObservableCollection<string>(this.strings);
        }
    }

The very simple unit test code is

    [TestMethod]
    public void TestMethod1()
    {
        var foo = new ObservableFoo(); // or new Foo()

        Assert.AreNotEqual(0, foo.Id);
        Assert.AreNotEqual(0, foo.Strings.Count);
    }

The only downside is that when I used ReadOnlyObservableCollection the test project got this compile error

The type 'System.Collections.ObjectModel.ReadOnlyObservableCollection`1' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes'

So in this case, using ReadOnlyObservableCollection would force users to add a reference to System.Windows which is a downside.

Edit: I came up with a solution that I posted on my blog - see How to make a library portable and data binding friendly at the same time?

like image 255
Ron Jacobs Avatar asked Jul 22 '12 14:07

Ron Jacobs


2 Answers

Well, it depends. If you are writing a pure model library, it makes no sense to expose WPF-specific interfaces; this would force the users link against WPF libraries even if they don't need to. Even if it were not, it exposes something that the users are not going to need, which is not a good design IMHO.

If your library is not limited to model usage, I would split it into several parts: core needed for all usage scenarios, WPF-dependent part with WPF-specific interfaces, maybe ASP-specific part with ASP-specific features and so on. The users will pick the parts they need and use them.


Edit: as @Julien's comment states, ObservableCollection<T> is now as part of core, so including it won't make the users depend from the WPF-specific libraries. Nevertheless, the idea stays the same. For WPF usage, you often need to offer/work with specific features (ObservableCollection, INotifyPropertyChanged/DependencyObject, dependency properties, notifications in UI thread only and so on). This means that they belong to a separate, WPF-specific part of the project.

So you can make the library consist of several parts: Library.Core.dll containing functions needed for generic/model development, Library.WPF.dll dealing with WPF-specific stuff and using Library.Core.dll, maybe Library.Console.dll and Library.ASP.dll as well. Users of WPF will use Library.Core.dll and Library.WPF.dll, console programs might need Library.Core.dll and Library.Console.dll and so on.

like image 113
Vlad Avatar answered Nov 15 '22 11:11

Vlad


I think that the low-level components of your library should offer interfaces that make sense for those components, at that particular level of abstraction, without regard to how the various consumers of your API might need to adapt them for their own uses.

For example, if a composite WPF application would use your components, it would be wholly appropriate for those applications to encapsulate your components into a Model or View Model that adapts the IList<T> (or better still, IEnumerable<T>) offered by your components into an ObservableCollection<T> suitable for binding to a view.

A console application might not need such overhead, and could happily use the IEnumerable<T>.

As an aside, be careful even when exposing collections as IList<T>. This allows consumers of your library to add to and remove items from the list, for example, which might not be in the spirit of the interface.

like image 27
lesscode Avatar answered Nov 15 '22 12:11

lesscode