简体   繁体   English

C#类库集合ObservableCollection <T> vs Collection <T>

[英]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. 我正在创建一个类库,可以在许多情况下使用ASP.NET,控制台应用程序,其他类库和XAML目标,如Silverlight或WPF。

Initially I decided to expose collections as IList. 最初我决定将集合公开为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. 但是当使用XAML编写样本时,我发现如果我想让它很容易绑定到这些集合,我需要使用ObservableCollection。

What are my options? 我有什么选择?

I could make the library expose ObservableCollection and force that upon users who have nothing to do with XAML. 我可以让库暴露ObservableCollection并强制对与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 我可以使我的类通用,允许调用者指定他们想要的集合类型,只要它实现ICollection,也许默认为Collection

I could make a set of classes one that uses ObservableCollection and one that does not say Foo and ObservableFoo. 我可以创建一组使用ObservableCollection的类和一个不说Foo和ObservableFoo的类。

I could implement INotifyCollectionChanged in my class but that seems silly when ObservableCollection does it for me. 我可以在我的类中实现INotifyCollectionChanged但是当ObservableCollection为我做这件事时,这似乎很愚蠢。

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 在Foo课我有

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

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

In class ObservableFoo I have 在班级ObservableFoo我有

    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 唯一的缺点是,当我使用ReadOnlyObservableCollection时,测试项目得到了这个编译错误

The type 'System.Collections.ObjectModel.ReadOnlyObservableCollection`1' is defined in an assembly that is not referenced. 类型'System.Collections.ObjectModel.ReadOnlyObservableCollection`1'在未引用的程序集中定义。 You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' 您必须添加对程序集'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. 因此,在这种情况下,使用ReadOnlyObservableCollection将强制用户添加对System.Windows的引用,这是一个缺点。

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? 编辑:我想出了一个我在博客上发布的解决方案 - 请参阅如何使库可移植并且数据绑定同时友好?

Well, it depends. 这得看情况。 If you are writing a pure model library, it makes no sense to expose WPF-specific interfaces; 如果您正在编写纯模型库,那么公开WPF特定的接口是没有意义的; this would force the users link against WPF libraries even if they don't need to. 这会强制用户链接WPF库,即使他们不需要。 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. 如果您的库不限于模型使用,我会将其分为几个部分:所有使用场景所需的核心,具有WPF特定接口的WPF相关部分,可能具有ASP特定功能的ASP特定部分等等。 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. 编辑:正如@ Julien的评论所述, ObservableCollection<T>现在是核心的一部分,因此包含它不会使用户依赖于WPF特定的库。 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). 对于WPF用法,您经常需要提供/使用特定功能( ObservableCollectionINotifyPropertyChanged / DependencyObject ,依赖项属性,仅在UI线程中的通知等)。 This means that they belong to a separate, WPF-specific part of the project. 这意味着它们属于项目中特定于WPF的单独部分。

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. 因此,您可以使库包含几个部分:Library.Core.dll包含通用/模型开发所需的函数,Library.WPF.dll处理WPF特定的东西并使用Library.Core.dll,可能是Library.Console.dll和Library.ASP.dll一样。 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. WPF的用户将使用Library.Core.dll和Library.WPF.dll,控制台程序可能需要Library.Core.dll和Library.Console.dll等。

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. 我认为库的低级组件应该在特定的抽象级别提供对这些组件有意义的接口,而不考虑API的各种使用者可能需要如何使它们适合自己的用途。

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. 例如,如果复合WPF应用程序将使用您的组件,那么将这些组件封装到适合IList<T> (或更好的, IEnumerable<T> )的模型或视图模型中的应用程序将完全适合。您的组件成为适合绑定到视图的ObservableCollection<T>

A console application might not need such overhead, and could happily use the IEnumerable<T> . 控制台应用程序可能不需要这样的开销,并且可以愉快地使用IEnumerable<T>

As an aside, be careful even when exposing collections as IList<T> . 另外,即使将集合公开为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. 这允许您的库的使用者添加和删除列表中的项目,例如,这可能不符合界面的精神。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM