Index: HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs
===================================================================
--- HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs	(revision 12076)
+++ HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs	(working copy)
@@ -37,15 +37,12 @@
     public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
       get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
     }
-    public IValueLookupParameter<ResultCollection> ResultsParameter {
-      get { return (IValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    public IResultParameter<DataTable> QualityDistributionParameter {
+      get { return (IResultParameter<DataTable>)Parameters["Quality Distribution"]; }
     }
-    private ValueParameter<StringValue> HistogramNameParameter {
-      get { return (ValueParameter<StringValue>)Parameters["HistogramName"]; }
+    public IResultParameter<DataTableHistory> QualityDistributionHistoryParameter {
+      get { return (IResultParameter<DataTableHistory>)Parameters["Quality Distribution History"]; }
     }
-    private ValueParameter<BoolValue> StoreHistoryParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
-    }
     public ILookupParameter<IntValue> IterationsParameter {
       get { return (ILookupParameter<IntValue>)Parameters["Iterations"]; }
     }
@@ -52,6 +49,9 @@
     public IValueLookupParameter<IntValue> MaximumIterationsParameter {
       get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
     }
+    private ValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
+    }
     #endregion
 
     public virtual bool EnabledByDefault {
@@ -58,11 +58,6 @@
       get { return true; }
     }
 
-    public string HistogramName {
-      get { return HistogramNameParameter.Value.Value; }
-      set { HistogramNameParameter.Value.Value = value; }
-    }
-
     public bool StoreHistory {
       get { return StoreHistoryParameter.Value.Value; }
       set { StoreHistoryParameter.Value.Value = value; }
@@ -76,16 +71,26 @@
     public QualityDistributionAnalyzer()
       : base() {
       Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
-      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The results collection where the analysis values should be stored."));
-      Parameters.Add(new FixedValueParameter<StringValue>("HistogramName", "The name of the histogram that gets injected in to the results collection.", new StringValue("Quality Distribution")));
+      Parameters.Add(new ResultParameter<DataTable>("Quality Distribution", "Shows the quality distributions in the current population."));
+      Parameters.Add(new ResultParameter<DataTableHistory>("Quality Distribution History", "Maintains the history of the quality distributions of each iteration."));
       Parameters.Add(new FixedValueParameter<BoolValue>("StoreHistory", "True if the history should be stored in addition to the current distribution", new BoolValue(false)));
       Parameters.Add(new LookupParameter<IntValue>("Iterations", "Optional: A value indicating the current iteration."));
       Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "Unused", new IntValue(-1)));
 
       QualityParameter.Hidden = true;
-      ResultsParameter.Hidden = true;
       IterationsParameter.Hidden = true;
       MaximumIterationsParameter.Hidden = true;
+
+      var table = new DataTable("Population Quality Distribution", QualityDistributionParameter.Description) {
+        VisualProperties = { XAxisTitle = "Quality", YAxisTitle = "Frequency" }
+      };
+      var row = new DataRow("QualityDistribution") {
+        VisualProperties = { ChartType = DataRowVisualProperties.DataRowChartType.Histogram }
+      };
+      table.Rows.Add(row);
+      QualityDistributionParameter.DefaultValue = table;
+
+      QualityDistributionHistoryParameter.DefaultValue = new DataTableHistory();
     }
 
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -93,43 +98,22 @@
     }
 
     public override IOperation Apply() {
-      DataTable qualityDistribution = null;
-      ResultCollection results = ResultsParameter.ActualValue;
-      string description = "Shows the quality distributions in the current population.";
-      if (results.ContainsKey(HistogramName)) {
-        qualityDistribution = results[HistogramName].Value as DataTable;
-      } else {
-        qualityDistribution = new DataTable("Population Quality Distribution", description);
-        qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName;
-        qualityDistribution.VisualProperties.YAxisTitle = "Frequency";
-        results.Add(new Result(HistogramName, description, qualityDistribution));
-      }
-      DataRow row;
-      if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row)) {
-        row = new DataRow("QualityDistribution");
-        row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
-        qualityDistribution.Rows.Add(row);
-      }
+      var qualityDistribution = QualityDistributionParameter.ActualValue;
+      var row = qualityDistribution.Rows.First();
+
       var qualities = QualityParameter.ActualValue;
       row.Values.Replace(qualities.Select(x => x.Value));
 
       if (StoreHistory) {
-        string historyResultName = HistogramName + " History";
-        DataTableHistory qdHistory = null;
-        if (results.ContainsKey(historyResultName)) {
-          qdHistory = results[historyResultName].Value as DataTableHistory;
-        } else {
-          qdHistory = new DataTableHistory();
-          results.Add(new Result(historyResultName, qdHistory));
-        }
-        DataTable table = (DataTable)qualityDistribution.Clone();
-        IntValue iteration = IterationsParameter.ActualValue;
+        var qdHistory = QualityDistributionHistoryParameter.ActualValue;
+        var table = (DataTable)qualityDistribution.Clone();
+        var iteration = IterationsParameter.ActualValue;
         if (iteration != null) {
-          string iterationName = IterationsParameter.ActualName;
+          var iterationName = IterationsParameter.ActualName;
           if (iterationName.EndsWith("s")) iterationName = iterationName.Remove(iterationName.Length - 1);
-          string appendix = " at " + iterationName + " " + iteration.Value.ToString();
+          var appendix = " at " + iterationName + " " + iteration.Value;
           table.Name += appendix;
-          table.Rows["QualityDistribution"].VisualProperties.DisplayName += appendix;
+          table.Rows.First().VisualProperties.DisplayName += appendix;
         }
         qdHistory.Add(table);
       }
Index: HeuristicLab.Core/3.3/HeuristicLab.Core-3.3.csproj
===================================================================
--- HeuristicLab.Core/3.3/HeuristicLab.Core-3.3.csproj	(revision 12076)
+++ HeuristicLab.Core/3.3/HeuristicLab.Core-3.3.csproj	(working copy)
@@ -161,7 +161,9 @@
     <Compile Include="Interfaces\DirectedGraph\IVertex.cs" />
     <Compile Include="Interfaces\ICheckedMultiOperator.cs" />
     <Compile Include="Interfaces\IConstrainedValueParameter.cs" />
+    <Compile Include="Interfaces\IContextualParameter.cs" />
     <Compile Include="Interfaces\IInstrumentedOperator.cs" />
+    <Compile Include="Interfaces\IResultParameter.cs" />
     <Compile Include="Interfaces\IMultiOperator.cs" />
     <Compile Include="Interfaces\IFixedValueParameter.cs" />
     <Compile Include="Interfaces\IOperatorGraphOperator.cs" />
Index: HeuristicLab.Core/3.3/Interfaces/IContextualParameter.cs
===================================================================
--- HeuristicLab.Core/3.3/Interfaces/IContextualParameter.cs	(revision 0)
+++ HeuristicLab.Core/3.3/Interfaces/IContextualParameter.cs	(working copy)
@@ -0,0 +1,26 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Core {
+  public interface IContextualParameter : IParameter {
+    IExecutionContext ExecutionContext { get; set; }
+  }
+}
Index: HeuristicLab.Core/3.3/Interfaces/ILookupParameter.cs
===================================================================
--- HeuristicLab.Core/3.3/Interfaces/ILookupParameter.cs	(revision 12076)
+++ HeuristicLab.Core/3.3/Interfaces/ILookupParameter.cs	(working copy)
@@ -22,10 +22,9 @@
 using System;
 
 namespace HeuristicLab.Core {
-  public interface ILookupParameter : IParameter {
+  public interface ILookupParameter : IContextualParameter {
     string ActualName { get; set; }
     string TranslatedName { get; }
-    IExecutionContext ExecutionContext { get; set; }
     event EventHandler ActualNameChanged;
   }
 
Index: HeuristicLab.Core/3.3/Interfaces/IResultParameter.cs
===================================================================
--- HeuristicLab.Core/3.3/Interfaces/IResultParameter.cs	(revision 0)
+++ HeuristicLab.Core/3.3/Interfaces/IResultParameter.cs	(working copy)
@@ -0,0 +1,36 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+
+namespace HeuristicLab.Core {
+  public interface IResultParameter : IContextualParameter {
+    string ResultName { get; set; }
+    string ResultCollectionName { get; set; }
+    event EventHandler ResultNameChanged;
+    event EventHandler ResultCollectionNameChanged;
+  }
+
+  public interface IResultParameter<T> : IResultParameter where T : class, IItem, new() {
+    T DefaultValue { get; set; }
+    new T ActualValue { get; set; }
+  }
+}
Index: HeuristicLab.Operators/3.3/Operator.cs
===================================================================
--- HeuristicLab.Operators/3.3/Operator.cs	(revision 12076)
+++ HeuristicLab.Operators/3.3/Operator.cs	(working copy)
@@ -119,14 +119,13 @@
       try {
         ExecutionContext = context;
         this.cancellationToken = cancellationToken;
-        foreach (ILookupParameter param in Parameters.OfType<ILookupParameter>())
+        foreach (var param in Parameters.OfType<IContextualParameter>())
           param.ExecutionContext = context;
         IOperation next = Apply();
         OnExecuted();
         return next;
-      }
-      finally {
-        foreach (ILookupParameter param in Parameters.OfType<ILookupParameter>())
+      } finally {
+        foreach (var param in Parameters.OfType<IContextualParameter>())
           param.ExecutionContext = null;
         ExecutionContext = null;
       }
Index: HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj
===================================================================
--- HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 12076)
+++ HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(working copy)
@@ -164,6 +164,7 @@
     <Compile Include="Interfaces\ISolutionSimilarityCalculator.cs" />
     <Compile Include="MetaOptimizers\BatchRun.cs" />
     <Compile Include="MetaOptimizers\Experiment.cs" />
+    <Compile Include="Parameters\ResultParameter.cs" />
     <Compile Include="RunCollectionModification\RunCollectionRunRemover.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="RunCollectionModification\RunCollectionDiscretizer.cs" />
Index: HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs
===================================================================
--- HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs	(revision 0)
+++ HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs	(working copy)
@@ -0,0 +1,230 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  [Item("ResultParameter", "A parameter whose value is written to a result collection.")]
+  [StorableClass]
+  public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() {
+
+    [Storable]
+    private string resultName;
+    public string ResultName {
+      get { return resultName; }
+      set {
+        if (value == null) throw new ArgumentNullException();
+        if (string.IsNullOrWhiteSpace(value)) {
+          resultName = Name;
+          OnResultNameChanged();
+        } else if (!resultName.Equals(value)) {
+          resultName = value;
+          OnResultNameChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private string resultCollectionName;
+    public string ResultCollectionName {
+      get { return resultCollectionName; }
+      set {
+        if (value == null) throw new ArgumentNullException("value");
+        if (string.IsNullOrWhiteSpace(value)) {
+          resultCollectionName = "Results";
+          OnResultCollectionNameChanged();
+        } else if (!resultCollectionName.Equals(value)) {
+          resultCollectionName = value;
+          OnResultCollectionNameChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private T defaultValue;
+    public T DefaultValue {
+      get { return defaultValue; }
+      set {
+        if (value != defaultValue) {
+          defaultValue = value;
+          OnDefaultValueChanged();
+        }
+      }
+    }
+
+    public new T ActualValue {
+      get { return (T)base.ActualValue; }
+      set { base.ActualValue = value; }
+    }
+
+    private Lazy<ThreadLocal<IItem>> cachedActualValues;
+    private IItem CachedActualValue {
+      get { return cachedActualValues.Value.Value; }
+    }
+
+    private Lazy<ThreadLocal<IExecutionContext>> executionContexts;
+    public IExecutionContext ExecutionContext {
+      get { return executionContexts.Value.Value; }
+      set {
+        executionContexts.Value.Value = value;
+        cachedActualValues.Value.Value = null;
+      }
+    }
+
+    [StorableConstructor]
+    private ResultParameter(bool deserializing) : base(deserializing) { }
+    private ResultParameter(ResultParameter<T> original, Cloner cloner)
+      : base(original, cloner) {
+      resultName = original.resultName;
+      resultCollectionName = original.resultCollectionName;
+      defaultValue = cloner.Clone(original.defaultValue);
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ResultParameter<T>(this, cloner);
+    }
+    public ResultParameter() : this("Anonymous") { }
+    public ResultParameter(string name)
+      : base(name, typeof(T)) {
+      resultName = Name;
+      resultCollectionName = "Results";
+      defaultValue = new T();
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description) : this(name, description, new T()) { }
+    public ResultParameter(string name, string description, T defaultValue)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      resultName = Name;
+      resultCollectionName = "Results";
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { }
+    public ResultParameter(string name, string description, T defaultValue, string resultName)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
+      resultCollectionName = "Results";
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { }
+    public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
+      this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName;
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+
+    public override string ToString() {
+      if (Name.Equals(ResultName)) return Name;
+      return Name + ": " + ResultName;
+    }
+
+
+    private ResultCollection LookupResultCollection() {
+      var scope = ExecutionContext.Scope;
+      while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName)
+        && !(scope.Variables[ResultCollectionName].Value is ResultCollection))
+        scope = scope.Parent;
+      return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null;
+    }
+
+    protected override IItem GetActualValue() {
+      if (CachedActualValue != null) return CachedActualValue;
+
+      var results = LookupResultCollection();
+      if (results == null)
+        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
+
+      if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone()));
+      var resultValue = results[ResultName].Value;
+      if (!(resultValue is T))
+        throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName()));
+
+      cachedActualValues.Value.Value = resultValue;
+      return resultValue;
+    }
+
+    protected override void SetActualValue(IItem value) {
+      if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName()));
+
+      var results = LookupResultCollection();
+      if (results == null)
+        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
+
+      if (!results.ContainsKey(ResultName))
+        results.Add(new Result(ResultName, value));
+      else results[ResultName].Value = value;
+
+      cachedActualValues.Value.Value = value;
+    }
+
+    public event EventHandler ResultNameChanged;
+    private void OnResultNameChanged() {
+      var handler = ResultNameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnToStringChanged();
+    }
+
+    public event EventHandler ResultCollectionNameChanged;
+    private void OnResultCollectionNameChanged() {
+      var handler = ResultCollectionNameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    public event EventHandler DefaultValueChanged;
+    private void OnDefaultValueChanged() {
+      EventHandler handler = DefaultValueChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnItemImageChanged();
+    }
+
+    #region IStatefulItem members
+    public void InitializeState() {
+    }
+
+    public void ClearState() {
+      if (cachedActualValues.IsValueCreated) {
+        cachedActualValues.Value.Dispose();
+        cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      }
+      if (executionContexts.IsValueCreated) {
+        executionContexts.Value.Dispose();
+        executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      }
+    }
+    #endregion
+  }
+}
Index: HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs
===================================================================
--- HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs	(revision 0)
+++ HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs	(working copy)
@@ -0,0 +1,230 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  [Item("ResultParameter", "A parameter whose value is written to a result collection.")]
+  [StorableClass]
+  public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() {
+
+    [Storable]
+    private string resultName;
+    public string ResultName {
+      get { return resultName; }
+      set {
+        if (value == null) throw new ArgumentNullException();
+        if (string.IsNullOrWhiteSpace(value)) {
+          resultName = Name;
+          OnResultNameChanged();
+        } else if (!resultName.Equals(value)) {
+          resultName = value;
+          OnResultNameChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private string resultCollectionName;
+    public string ResultCollectionName {
+      get { return resultCollectionName; }
+      set {
+        if (value == null) throw new ArgumentNullException("value");
+        if (string.IsNullOrWhiteSpace(value)) {
+          resultCollectionName = "Results";
+          OnResultCollectionNameChanged();
+        } else if (!resultCollectionName.Equals(value)) {
+          resultCollectionName = value;
+          OnResultCollectionNameChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private T defaultValue;
+    public T DefaultValue {
+      get { return defaultValue; }
+      set {
+        if (value != defaultValue) {
+          defaultValue = value;
+          OnDefaultValueChanged();
+        }
+      }
+    }
+
+    public new T ActualValue {
+      get { return (T)base.ActualValue; }
+      set { base.ActualValue = value; }
+    }
+
+    private Lazy<ThreadLocal<IItem>> cachedActualValues;
+    private IItem CachedActualValue {
+      get { return cachedActualValues.Value.Value; }
+    }
+
+    private Lazy<ThreadLocal<IExecutionContext>> executionContexts;
+    public IExecutionContext ExecutionContext {
+      get { return executionContexts.Value.Value; }
+      set {
+        executionContexts.Value.Value = value;
+        cachedActualValues.Value.Value = null;
+      }
+    }
+
+    [StorableConstructor]
+    private ResultParameter(bool deserializing) : base(deserializing) { }
+    private ResultParameter(ResultParameter<T> original, Cloner cloner)
+      : base(original, cloner) {
+      resultName = original.resultName;
+      resultCollectionName = original.resultCollectionName;
+      defaultValue = cloner.Clone(original.defaultValue);
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ResultParameter<T>(this, cloner);
+    }
+    public ResultParameter() : this("Anonymous") { }
+    public ResultParameter(string name)
+      : base(name, typeof(T)) {
+      resultName = Name;
+      resultCollectionName = "Results";
+      defaultValue = new T();
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description) : this(name, description, new T()) { }
+    public ResultParameter(string name, string description, T defaultValue)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      resultName = Name;
+      resultCollectionName = "Results";
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { }
+    public ResultParameter(string name, string description, T defaultValue, string resultName)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
+      resultCollectionName = "Results";
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+    public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { }
+    public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName)
+      : base(name, description, typeof(T)) {
+      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
+      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
+      this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName;
+      this.defaultValue = defaultValue;
+      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+    }
+
+    public override string ToString() {
+      if (Name.Equals(ResultName)) return Name;
+      return Name + ": " + ResultName;
+    }
+
+
+    private ResultCollection LookupResultCollection() {
+      var scope = ExecutionContext.Scope;
+      while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName)
+        && !(scope.Variables[ResultCollectionName].Value is ResultCollection))
+        scope = scope.Parent;
+      return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null;
+    }
+
+    protected override IItem GetActualValue() {
+      if (CachedActualValue != null) return CachedActualValue;
+
+      var results = LookupResultCollection();
+      if (results == null)
+        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
+
+      if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone()));
+      var resultValue = results[ResultName].Value;
+      if (!(resultValue is T))
+        throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName()));
+
+      cachedActualValues.Value.Value = resultValue;
+      return resultValue;
+    }
+
+    protected override void SetActualValue(IItem value) {
+      if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName()));
+
+      var results = LookupResultCollection();
+      if (results == null)
+        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
+
+      if (!results.ContainsKey(ResultName))
+        results.Add(new Result(ResultName, value));
+      else results[ResultName].Value = value;
+
+      cachedActualValues.Value.Value = value;
+    }
+
+    public event EventHandler ResultNameChanged;
+    private void OnResultNameChanged() {
+      var handler = ResultNameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnToStringChanged();
+    }
+
+    public event EventHandler ResultCollectionNameChanged;
+    private void OnResultCollectionNameChanged() {
+      var handler = ResultCollectionNameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    public event EventHandler DefaultValueChanged;
+    private void OnDefaultValueChanged() {
+      EventHandler handler = DefaultValueChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnItemImageChanged();
+    }
+
+    #region IStatefulItem members
+    public void InitializeState() {
+    }
+
+    public void ClearState() {
+      if (cachedActualValues.IsValueCreated) {
+        cachedActualValues.Value.Dispose();
+        cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      }
+      if (executionContexts.IsValueCreated) {
+        executionContexts.Value.Dispose();
+        executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
+      }
+    }
+    #endregion
+  }
+}
