Index: Core/Common/src/Core.Common.Base/Observable.cs =================================================================== diff -u -r1e4d2363eb853577139c402364c4462dad821046 -r94ef875f26bff005b1d53880c92f350b373a31ec --- Core/Common/src/Core.Common.Base/Observable.cs (.../Observable.cs) (revision 1e4d2363eb853577139c402364c4462dad821046) +++ Core/Common/src/Core.Common.Base/Observable.cs (.../Observable.cs) (revision 94ef875f26bff005b1d53880c92f350b373a31ec) @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace Core.Common.Base { @@ -35,8 +36,15 @@ /// public void NotifyObservers() { - foreach (var observer in observers) + // Iterate through a copy of the list of observers; an update of one observer might result in detaching another observer (which will result in a "list modified" exception over here otherwise) + foreach (var observer in observers.ToList()) { + // Ensure the observer is still part of the original list of observers + if (!observers.Contains(observer)) + { + continue; + } + observer.UpdateObserver(); } } Index: Core/Common/src/Core.Common.Base/Project.cs =================================================================== diff -u -r04f06b5762b758295a52944dd232394a462cf72c -r94ef875f26bff005b1d53880c92f350b373a31ec --- Core/Common/src/Core.Common.Base/Project.cs (.../Project.cs) (revision 04f06b5762b758295a52944dd232394a462cf72c) +++ Core/Common/src/Core.Common.Base/Project.cs (.../Project.cs) (revision 94ef875f26bff005b1d53880c92f350b373a31ec) @@ -1,13 +1,11 @@ -using System.Collections.Generic; -using System.Linq; using Core.Common.Utils.Collections.Generic; namespace Core.Common.Base { /// /// Container of all data and tasks. /// - public class Project : IObservable + public class Project : Observable { /// /// Creates instance of the Project. @@ -39,29 +37,5 @@ /// The items in the project. /// public IEventedList Items { get; private set; } - - # region IObservable - - private readonly IList observers = new List(); - - public void Attach(IObserver observer) - { - observers.Add(observer); - } - - public void Detach(IObserver observer) - { - observers.Remove(observer); - } - - public void NotifyObservers() - { - foreach (var observer in observers.ToList()) // Copy the list of observers; an update of one observer might result in detaching another observer (which will result in a "list modified" exception over here otherwise) - { - observer.UpdateObserver(); - } - } - - # endregion } } \ No newline at end of file Index: Core/Common/test/Core.Common.Base.Tests/Core.Common.Base.Tests.csproj =================================================================== diff -u -ree60be046a1b4e4151bb567e9a9c3ab0876d3b55 -r94ef875f26bff005b1d53880c92f350b373a31ec --- Core/Common/test/Core.Common.Base.Tests/Core.Common.Base.Tests.csproj (.../Core.Common.Base.Tests.csproj) (revision ee60be046a1b4e4151bb567e9a9c3ab0876d3b55) +++ Core/Common/test/Core.Common.Base.Tests/Core.Common.Base.Tests.csproj (.../Core.Common.Base.Tests.csproj) (revision 94ef875f26bff005b1d53880c92f350b373a31ec) @@ -123,6 +123,7 @@ + True True Index: Core/Common/test/Core.Common.Base.Tests/ObservableTest.cs =================================================================== diff -u --- Core/Common/test/Core.Common.Base.Tests/ObservableTest.cs (revision 0) +++ Core/Common/test/Core.Common.Base.Tests/ObservableTest.cs (revision 94ef875f26bff005b1d53880c92f350b373a31ec) @@ -0,0 +1,51 @@ +using System; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Common.Base.Tests +{ + [TestFixture] + public class ObservableTest + { + [Test] + public void NotifyObservers_MultipleObserversDetachingOrAttachingOthers_NoUpdatesForAttachedAndDetachedObservers() + { + // Setup + var mocks = new MockRepository(); + var testObservable = new TestObservable(); + + var observer1 = mocks.Stub(); + var observer2 = mocks.Stub(); + var observer3 = mocks.Stub(); + var observer4 = mocks.Stub(); + var observer5 = mocks.Stub(); + var observer6 = mocks.Stub(); + + testObservable.Attach(observer1); + testObservable.Attach(observer2); + testObservable.Attach(observer3); + testObservable.Attach(observer4); + testObservable.Attach(observer6); + + observer1.Expect(o => o.UpdateObserver()).Repeat.Once(); + observer2.Expect(o => o.UpdateObserver()).Do((Action) (() => testObservable.Detach(observer3))).Repeat.Once(); + observer3.Expect(o => o.UpdateObserver()).Repeat.Never(); // A detached observer should no longer be updated + observer4.Expect(o => o.UpdateObserver()).Do((Action)(() => testObservable.Attach(observer5))).Repeat.Once(); + observer5.Expect(o => o.UpdateObserver()).Repeat.Never(); // An attached observer should not be updated too + observer6.Expect(o => o.UpdateObserver()).Repeat.Once(); + + mocks.ReplayAll(); + + // Call + testObservable.NotifyObservers(); + + // Assert + mocks.VerifyAll(); + } + + private class TestObservable : Observable + { + + } + } +}