问题描述:

I have a thread safe observable collection replacement which I would like to write a unit test for. To avoid a false positive I'm trying to write a multi-threaded test that proves an object cannot be added to an ObservableCollection<> without failing so I can swap it with mine and watch it go green. I just cannot get this test to fail (using NUnit).

In no particular order I've so far tried:

  • Creating the collection on a different thread and updating on current
  • Creating the collection on the current thread and updating on an alternate
  • Using different threading mechanisms

    • ThreadStart
    • Dispatcher
    • BackgroundWorker
  • Using different apartment states

    • All combinations of STA and MTA on the test itself and/or one or both of the threads
  • Creating a WPF Window to hold the collection and manipulating the Dispatcher frames manually to simulate a runtime environment.

The custom collection itself is working fine in real code so this is now more of an academic exercise than anything; My threading confidence has been shaken :)

网友答案:

You're trying to test something that is not there...

There is no reason for this test to fail, because the ObservableCollection<T> class itself doesn't have thread affinity. It's not thread-safe, but it just means the behavior will be unpredictable if you use it in a multithread scenario without proper locking; there is nothing in ObservableCollection<T> that will explicitly throw an exception if you do this.

However, the CollectionView class does have thread affinity, which is why you can't add items to an ObservableCollection<T> from a different thread if there is a CollectionView attached to it (which happens, for instance, when you bind an ItemsControl to the collection). But it's the CollectionView that throws an exception, not the ObservableCollection<T>...

Take the following code:

var list = new ObservableCollection<string>();
// var view = CollectionViewSource.GetDefaultView(list);
ThreadPool.QueueUserWorkItem(_ => list.Add("foo"));

It executes without throwing an exception, but if you uncomment the line that creates the CollectionView, it will throw a NotSupportedException:

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

相关阅读:
Top