Index: branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 16692)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 16723)
@@ -1,5 +1,5 @@
 #region License Information
 /* HeuristicLab
- * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
  *
  * This file is part of HeuristicLab.
@@ -29,7 +29,8 @@
 using HeuristicLab.Core;
 using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HEAL.Attic;
 
 namespace HeuristicLab.Optimization {
+  [StorableType("3d385be2-5c83-43f2-a693-f984acac44f6")]
   internal enum BatchRunAction { None, Prepare, Start, Pause, Stop };
 
@@ -39,5 +40,5 @@
   [Item("Batch Run", "A run in which an optimizer is executed a given number of times.")]
   [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 110)]
-  [StorableClass]
+  [StorableType("E85407E0-18EC-4198-8321-9CF030FDF6D7")]
   public sealed class BatchRun : NamedItem, IOptimizer, IStorableContent {
     public string Filename { get; set; }
@@ -199,5 +200,5 @@
     }
     [StorableConstructor]
-    private BatchRun(bool deserializing) : base(deserializing) { }
+    private BatchRun(StorableConstructorFlag _) : base(_) { }
     [StorableHook(HookType.AfterDeserialization)]
     private void AfterDeserialization() {
Index: branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 16692)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 16723)
@@ -1,5 +1,5 @@
 #region License Information
 /* HeuristicLab
- * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
  *
  * This file is part of HeuristicLab.
@@ -29,5 +29,5 @@
 using HeuristicLab.Common;
 using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HEAL.Attic;
 
 namespace HeuristicLab.Optimization {
@@ -37,5 +37,5 @@
   [Item("Experiment", "An experiment which contains multiple algorithms, batch runs or other experiments.")]
   [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 100)]
-  [StorableClass]
+  [StorableType("A8A4536B-54C1-4A17-AB58-A6006F7F394B")]
   public sealed class Experiment : NamedItem, IOptimizer, IStorableContent {
     public string Filename { get; set; }
@@ -161,5 +161,5 @@
     }
     [StorableConstructor]
-    private Experiment(bool deserializing) : base(deserializing) { }
+    private Experiment(StorableConstructorFlag _) : base(_) { }
     [StorableHook(HookType.AfterDeserialization)]
     private void AfterDeserialization() {
Index: branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 16692)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 16723)
@@ -1,5 +1,5 @@
 ﻿#region License Information
 /* HeuristicLab
- * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
  *
  * This file is part of HeuristicLab.
@@ -27,9 +27,9 @@
 using System.Threading;
 using System.Threading.Tasks;
+using HEAL.Attic;
 using HeuristicLab.Collections;
 using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
 using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
 namespace HeuristicLab.Optimization {
@@ -39,5 +39,5 @@
   [Item("Timelimit Run", "A run in which an optimizer is executed a certain maximum time.")]
   [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 115)]
-  [StorableClass]
+  [StorableType("85A1AB82-689F-4925-B888-B3886707BE88")]
   public sealed class TimeLimitRun : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
     public string Filename { get; set; }
@@ -62,5 +62,5 @@
         if (maximumExecutionTime == value) return;
         maximumExecutionTime = value;
-        OnPropertyChanged("MaximumExecutionTime");
+        OnPropertyChanged(nameof(MaximumExecutionTime));
       }
     }
@@ -77,5 +77,5 @@
         snapshotTimes.Sort();
         FindNextSnapshotTimeIndex(ExecutionTime);
-        OnPropertyChanged("SnapshotTimes");
+        OnPropertyChanged(nameof(SnapshotTimes));
       }
     }
@@ -89,5 +89,5 @@
         if (storeAlgorithmInEachSnapshot == value) return;
         storeAlgorithmInEachSnapshot = value;
-        OnPropertyChanged("StoreAlgorithmInEachSnapshot");
+        OnPropertyChanged(nameof(StoreAlgorithmInEachSnapshot));
       }
     }
@@ -100,11 +100,19 @@
         if (snapshots == value) return;
         snapshots = value;
-        OnPropertyChanged("Snapshots");
+        OnPropertyChanged(nameof(Snapshots));
       }
     }
 
     #region Inherited Properties
+    [Storable]
+    private ExecutionState executionState;
     public ExecutionState ExecutionState {
-      get { return (Algorithm != null) ? Algorithm.ExecutionState : ExecutionState.Stopped; }
+      get { return executionState; }
+      private set {
+        if (executionState == value) return;
+        executionState = value;
+        OnExecutionStateChanged();
+        OnPropertyChanged(nameof(ExecutionState));
+      }
     }
 
@@ -119,11 +127,17 @@
       set {
         if (algorithm == value) return;
+        if (ExecutionState == ExecutionState.Started || ExecutionState == ExecutionState.Paused)
+          throw new InvalidOperationException("Cannot change algorithm while the TimeLimitRun is running or paused.");
         if (algorithm != null) DeregisterAlgorithmEvents();
         algorithm = value;
+        if (algorithm != null) RegisterAlgorithmEvents();
+        OnPropertyChanged(nameof(Algorithm));
+        OnPropertyChanged(nameof(NestedOptimizers));
         if (algorithm != null) {
-          RegisterAlgorithmEvents();
-        }
-        OnPropertyChanged("Algorithm");
-        Prepare();
+          if (algorithm.ExecutionState == ExecutionState.Started || algorithm.ExecutionState == ExecutionState.Paused)
+            throw new InvalidOperationException("Cannot assign a running or paused algorithm to a TimeLimitRun.");
+          Prepare();
+          if (algorithm.ExecutionState == ExecutionState.Stopped) OnStopped();
+        } else OnStopped();
       }
     }
@@ -137,5 +151,5 @@
         if (runs == value) return;
         runs = value;
-        OnPropertyChanged("Runs");
+        OnPropertyChanged(nameof(Runs));
       }
     }
@@ -152,5 +166,5 @@
 
     [StorableConstructor]
-    private TimeLimitRun(bool deserializing) : base(deserializing) { }
+    private TimeLimitRun(StorableConstructorFlag _) : base(_) { }
     private TimeLimitRun(TimeLimitRun original, Cloner cloner)
       : base(original, cloner) {
@@ -160,4 +174,5 @@
       snapshots = cloner.Clone(original.snapshots);
       storeAlgorithmInEachSnapshot = original.storeAlgorithmInEachSnapshot;
+      executionState = original.executionState;
       algorithm = cloner.Clone(original.algorithm);
       runs = cloner.Clone(original.runs);
@@ -169,4 +184,5 @@
       name = ItemName;
       description = ItemDescription;
+      executionState = ExecutionState.Stopped;
       maximumExecutionTime = TimeSpan.FromMinutes(.5);
       snapshotTimes = new ObservableList<TimeSpan>(new[] {
@@ -182,4 +198,5 @@
       : base(name) {
       description = ItemDescription;
+      executionState = ExecutionState.Stopped;
       maximumExecutionTime = TimeSpan.FromMinutes(.5);
       snapshotTimes = new ObservableList<TimeSpan>(new[] {
@@ -188,4 +205,5 @@
           TimeSpan.FromSeconds(15) });
       snapshotTimesIndex = 0;
+      snapshots = new RunCollection();
       Runs = new RunCollection { OptimizerName = Name };
       Initialize();
@@ -193,4 +211,5 @@
     public TimeLimitRun(string name, string description)
       : base(name, description) {
+      executionState = ExecutionState.Stopped;
       maximumExecutionTime = TimeSpan.FromMinutes(.5);
       snapshotTimes = new ObservableList<TimeSpan>(new[] {
@@ -199,4 +218,5 @@
           TimeSpan.FromSeconds(15) });
       snapshotTimesIndex = 0;
+      snapshots = new RunCollection();
       Runs = new RunCollection { OptimizerName = Name };
       Initialize();
@@ -211,4 +231,10 @@
     private void AfterDeserialization() {
       Initialize();
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (Algorithm != null && executionState != Algorithm.ExecutionState) {
+        executionState = Algorithm.ExecutionState;
+      } else if (Algorithm == null) executionState = ExecutionState.Stopped;
+      #endregion
     }
 
@@ -236,4 +262,5 @@
     }
     public void Prepare(bool clearRuns) {
+      if (Algorithm == null) return;
       Algorithm.Prepare(clearRuns);
     }
@@ -280,4 +307,5 @@
     public event EventHandler Prepared;
     private void OnPrepared() {
+      ExecutionState = ExecutionState.Prepared;
       var handler = Prepared;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -285,4 +313,5 @@
     public event EventHandler Started;
     private void OnStarted() {
+      ExecutionState = ExecutionState.Started;
       var handler = Started;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -290,4 +319,5 @@
     public event EventHandler Paused;
     private void OnPaused() {
+      ExecutionState = ExecutionState.Paused;
       var handler = Paused;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -295,4 +325,5 @@
     public event EventHandler Stopped;
     private void OnStopped() {
+      ExecutionState = ExecutionState.Stopped;
       var handler = Stopped;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -300,4 +331,5 @@
     public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
     private void OnExceptionOccurred(Exception exception) {
+      ExecutionState = ExecutionState.Paused;
       var handler = ExceptionOccurred;
       if (handler != null) handler(this, new EventArgs<Exception>(exception));
@@ -309,5 +341,4 @@
       algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
       algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
-      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
       algorithm.Paused += Algorithm_Paused;
       algorithm.Prepared += Algorithm_Prepared;
@@ -318,5 +349,4 @@
       algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
       algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
-      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
       algorithm.Paused -= Algorithm_Paused;
       algorithm.Prepared -= Algorithm_Prepared;
@@ -338,7 +368,4 @@
       }
       OnExecutionTimeChanged();
-    }
-    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
-      OnExecutionStateChanged();
     }
     private void Algorithm_Paused(object sender, EventArgs e) {
@@ -348,6 +375,5 @@
         MakeSnapshot();
         FindNextSnapshotTimeIndex(ExecutionTime);
-      }
-      OnPaused();
+      } else OnPaused();
       if (action == ExecutionState.Started) Algorithm.Start();
       else if (action == ExecutionState.Stopped) Algorithm.Stop();
@@ -359,14 +385,19 @@
     }
     private void Algorithm_Started(object sender, EventArgs e) {
-      OnStarted();
+      if (ExecutionState == ExecutionState.Prepared || ExecutionState == ExecutionState.Paused)
+        OnStarted();
+      if (ExecutionState == ExecutionState.Stopped)
+        throw new InvalidOperationException("Algorithm was started although TimeLimitRun was in state Stopped.");
+      // otherwise the algorithm was just started after being snapshotted
     }
     private void Algorithm_Stopped(object sender, EventArgs e) {
-      var cloner = new Cloner();
-      var algRun = cloner.Clone(Algorithm.Runs.Last());
-      var clonedSnapshots = cloner.Clone(snapshots);
-      algRun.Results.Add("TimeLimitRunSnapshots", clonedSnapshots);
-      Runs.Add(algRun);
-      Algorithm.Runs.Clear();
-      OnStopped();
+      try {
+        var cloner = new Cloner();
+        var algRun = cloner.Clone(Algorithm.Runs.Last());
+        var clonedSnapshots = cloner.Clone(snapshots);
+        algRun.Results.Add("TimeLimitRunSnapshots", clonedSnapshots);
+        Runs.Add(algRun);
+        Algorithm.Runs.Clear();
+      } finally { OnStopped(); }
     }
     #endregion
@@ -377,5 +408,5 @@
       while (index < snapshotTimes.Count && snapshotTimes[index] <= reference) {
         index++;
-      };
+      }
       snapshotTimesIndex = index;
     }
