Ticket #2281: resultparameter.patch
File resultparameter.patch, 34.5 KB (added by abeham, 9 years ago) |
---|
-
HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs
37 37 public IScopeTreeLookupParameter<DoubleValue> QualityParameter { 38 38 get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; } 39 39 } 40 public I ValueLookupParameter<ResultCollection> ResultsParameter {41 get { return (I ValueLookupParameter<ResultCollection>)Parameters["Results"]; }40 public IResultParameter<DataTable> QualityDistributionParameter { 41 get { return (IResultParameter<DataTable>)Parameters["Quality Distribution"]; } 42 42 } 43 p rivate ValueParameter<StringValue> HistogramNameParameter {44 get { return ( ValueParameter<StringValue>)Parameters["HistogramName"]; }43 public IResultParameter<DataTableHistory> QualityDistributionHistoryParameter { 44 get { return (IResultParameter<DataTableHistory>)Parameters["Quality Distribution History"]; } 45 45 } 46 private ValueParameter<BoolValue> StoreHistoryParameter {47 get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }48 }49 46 public ILookupParameter<IntValue> IterationsParameter { 50 47 get { return (ILookupParameter<IntValue>)Parameters["Iterations"]; } 51 48 } … … 52 49 public IValueLookupParameter<IntValue> MaximumIterationsParameter { 53 50 get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; } 54 51 } 52 private ValueParameter<BoolValue> StoreHistoryParameter { 53 get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; } 54 } 55 55 #endregion 56 56 57 57 public virtual bool EnabledByDefault { … … 58 58 get { return true; } 59 59 } 60 60 61 public string HistogramName {62 get { return HistogramNameParameter.Value.Value; }63 set { HistogramNameParameter.Value.Value = value; }64 }65 66 61 public bool StoreHistory { 67 62 get { return StoreHistoryParameter.Value.Value; } 68 63 set { StoreHistoryParameter.Value.Value = value; } … … 76 71 public QualityDistributionAnalyzer() 77 72 : base() { 78 73 Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution.")); 79 Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The results collection where the analysis values should be stored."));80 Parameters.Add(new FixedValueParameter<StringValue>("HistogramName", "The name of the histogram that gets injected in to the results collection.", new StringValue("Quality Distribution")));74 Parameters.Add(new ResultParameter<DataTable>("Quality Distribution", "Shows the quality distributions in the current population.")); 75 Parameters.Add(new ResultParameter<DataTableHistory>("Quality Distribution History", "Maintains the history of the quality distributions of each iteration.")); 81 76 Parameters.Add(new FixedValueParameter<BoolValue>("StoreHistory", "True if the history should be stored in addition to the current distribution", new BoolValue(false))); 82 77 Parameters.Add(new LookupParameter<IntValue>("Iterations", "Optional: A value indicating the current iteration.")); 83 78 Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "Unused", new IntValue(-1))); 84 79 85 80 QualityParameter.Hidden = true; 86 ResultsParameter.Hidden = true;87 81 IterationsParameter.Hidden = true; 88 82 MaximumIterationsParameter.Hidden = true; 83 84 var table = new DataTable("Population Quality Distribution", QualityDistributionParameter.Description) { 85 VisualProperties = { XAxisTitle = "Quality", YAxisTitle = "Frequency" } 86 }; 87 var row = new DataRow("QualityDistribution") { 88 VisualProperties = { ChartType = DataRowVisualProperties.DataRowChartType.Histogram } 89 }; 90 table.Rows.Add(row); 91 QualityDistributionParameter.DefaultValue = table; 92 93 QualityDistributionHistoryParameter.DefaultValue = new DataTableHistory(); 89 94 } 90 95 91 96 public override IDeepCloneable Clone(Cloner cloner) { … … 93 98 } 94 99 95 100 public override IOperation Apply() { 96 DataTable qualityDistribution = null; 97 ResultCollection results = ResultsParameter.ActualValue; 98 string description = "Shows the quality distributions in the current population."; 99 if (results.ContainsKey(HistogramName)) { 100 qualityDistribution = results[HistogramName].Value as DataTable; 101 } else { 102 qualityDistribution = new DataTable("Population Quality Distribution", description); 103 qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName; 104 qualityDistribution.VisualProperties.YAxisTitle = "Frequency"; 105 results.Add(new Result(HistogramName, description, qualityDistribution)); 106 } 107 DataRow row; 108 if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row)) { 109 row = new DataRow("QualityDistribution"); 110 row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram; 111 qualityDistribution.Rows.Add(row); 112 } 101 var qualityDistribution = QualityDistributionParameter.ActualValue; 102 var row = qualityDistribution.Rows.First(); 103 113 104 var qualities = QualityParameter.ActualValue; 114 105 row.Values.Replace(qualities.Select(x => x.Value)); 115 106 116 107 if (StoreHistory) { 117 string historyResultName = HistogramName + " History"; 118 DataTableHistory qdHistory = null; 119 if (results.ContainsKey(historyResultName)) { 120 qdHistory = results[historyResultName].Value as DataTableHistory; 121 } else { 122 qdHistory = new DataTableHistory(); 123 results.Add(new Result(historyResultName, qdHistory)); 124 } 125 DataTable table = (DataTable)qualityDistribution.Clone(); 126 IntValue iteration = IterationsParameter.ActualValue; 108 var qdHistory = QualityDistributionHistoryParameter.ActualValue; 109 var table = (DataTable)qualityDistribution.Clone(); 110 var iteration = IterationsParameter.ActualValue; 127 111 if (iteration != null) { 128 stringiterationName = IterationsParameter.ActualName;112 var iterationName = IterationsParameter.ActualName; 129 113 if (iterationName.EndsWith("s")) iterationName = iterationName.Remove(iterationName.Length - 1); 130 string appendix = " at " + iterationName + " " + iteration.Value.ToString();114 var appendix = " at " + iterationName + " " + iteration.Value; 131 115 table.Name += appendix; 132 table.Rows ["QualityDistribution"].VisualProperties.DisplayName += appendix;116 table.Rows.First().VisualProperties.DisplayName += appendix; 133 117 } 134 118 qdHistory.Add(table); 135 119 } -
HeuristicLab.Core/3.3/HeuristicLab.Core-3.3.csproj
161 161 <Compile Include="Interfaces\DirectedGraph\IVertex.cs" /> 162 162 <Compile Include="Interfaces\ICheckedMultiOperator.cs" /> 163 163 <Compile Include="Interfaces\IConstrainedValueParameter.cs" /> 164 <Compile Include="Interfaces\IContextualParameter.cs" /> 164 165 <Compile Include="Interfaces\IInstrumentedOperator.cs" /> 166 <Compile Include="Interfaces\IResultParameter.cs" /> 165 167 <Compile Include="Interfaces\IMultiOperator.cs" /> 166 168 <Compile Include="Interfaces\IFixedValueParameter.cs" /> 167 169 <Compile Include="Interfaces\IOperatorGraphOperator.cs" /> -
HeuristicLab.Core/3.3/Interfaces/IContextualParameter.cs
1 #region License Information 2 /* HeuristicLab 3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 * 5 * This file is part of HeuristicLab. 6 * 7 * HeuristicLab is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * HeuristicLab is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 #endregion 21 22 namespace HeuristicLab.Core { 23 public interface IContextualParameter : IParameter { 24 IExecutionContext ExecutionContext { get; set; } 25 } 26 } -
HeuristicLab.Core/3.3/Interfaces/ILookupParameter.cs
22 22 using System; 23 23 24 24 namespace HeuristicLab.Core { 25 public interface ILookupParameter : I Parameter {25 public interface ILookupParameter : IContextualParameter { 26 26 string ActualName { get; set; } 27 27 string TranslatedName { get; } 28 IExecutionContext ExecutionContext { get; set; }29 28 event EventHandler ActualNameChanged; 30 29 } 31 30 -
HeuristicLab.Core/3.3/Interfaces/IResultParameter.cs
1 #region License Information 2 /* HeuristicLab 3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 * 5 * This file is part of HeuristicLab. 6 * 7 * HeuristicLab is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * HeuristicLab is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 #endregion 21 22 using System; 23 24 namespace HeuristicLab.Core { 25 public interface IResultParameter : IContextualParameter { 26 string ResultName { get; set; } 27 string ResultCollectionName { get; set; } 28 event EventHandler ResultNameChanged; 29 event EventHandler ResultCollectionNameChanged; 30 } 31 32 public interface IResultParameter<T> : IResultParameter where T : class, IItem, new() { 33 T DefaultValue { get; set; } 34 new T ActualValue { get; set; } 35 } 36 } -
HeuristicLab.Operators/3.3/Operator.cs
119 119 try { 120 120 ExecutionContext = context; 121 121 this.cancellationToken = cancellationToken; 122 foreach ( ILookupParameter param in Parameters.OfType<ILookupParameter>())122 foreach (var param in Parameters.OfType<IContextualParameter>()) 123 123 param.ExecutionContext = context; 124 124 IOperation next = Apply(); 125 125 OnExecuted(); 126 126 return next; 127 } 128 finally { 129 foreach (ILookupParameter param in Parameters.OfType<ILookupParameter>()) 127 } finally { 128 foreach (var param in Parameters.OfType<IContextualParameter>()) 130 129 param.ExecutionContext = null; 131 130 ExecutionContext = null; 132 131 } -
HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj
164 164 <Compile Include="Interfaces\ISolutionSimilarityCalculator.cs" /> 165 165 <Compile Include="MetaOptimizers\BatchRun.cs" /> 166 166 <Compile Include="MetaOptimizers\Experiment.cs" /> 167 <Compile Include="Parameters\ResultParameter.cs" /> 167 168 <Compile Include="RunCollectionModification\RunCollectionRunRemover.cs" /> 168 169 <Compile Include="Plugin.cs" /> 169 170 <Compile Include="RunCollectionModification\RunCollectionDiscretizer.cs" /> -
HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs
1 #region License Information 2 /* HeuristicLab 3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 * 5 * This file is part of HeuristicLab. 6 * 7 * HeuristicLab is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * HeuristicLab is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 #endregion 21 22 using System; 23 using System.Threading; 24 using HeuristicLab.Common; 25 using HeuristicLab.Core; 26 using HeuristicLab.Parameters; 27 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 28 29 namespace HeuristicLab.Optimization { 30 [Item("ResultParameter", "A parameter whose value is written to a result collection.")] 31 [StorableClass] 32 public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() { 33 34 [Storable] 35 private string resultName; 36 public string ResultName { 37 get { return resultName; } 38 set { 39 if (value == null) throw new ArgumentNullException(); 40 if (string.IsNullOrWhiteSpace(value)) { 41 resultName = Name; 42 OnResultNameChanged(); 43 } else if (!resultName.Equals(value)) { 44 resultName = value; 45 OnResultNameChanged(); 46 } 47 } 48 } 49 50 [Storable] 51 private string resultCollectionName; 52 public string ResultCollectionName { 53 get { return resultCollectionName; } 54 set { 55 if (value == null) throw new ArgumentNullException("value"); 56 if (string.IsNullOrWhiteSpace(value)) { 57 resultCollectionName = "Results"; 58 OnResultCollectionNameChanged(); 59 } else if (!resultCollectionName.Equals(value)) { 60 resultCollectionName = value; 61 OnResultCollectionNameChanged(); 62 } 63 } 64 } 65 66 [Storable] 67 private T defaultValue; 68 public T DefaultValue { 69 get { return defaultValue; } 70 set { 71 if (value != defaultValue) { 72 defaultValue = value; 73 OnDefaultValueChanged(); 74 } 75 } 76 } 77 78 public new T ActualValue { 79 get { return (T)base.ActualValue; } 80 set { base.ActualValue = value; } 81 } 82 83 private Lazy<ThreadLocal<IItem>> cachedActualValues; 84 private IItem CachedActualValue { 85 get { return cachedActualValues.Value.Value; } 86 } 87 88 private Lazy<ThreadLocal<IExecutionContext>> executionContexts; 89 public IExecutionContext ExecutionContext { 90 get { return executionContexts.Value.Value; } 91 set { 92 executionContexts.Value.Value = value; 93 cachedActualValues.Value.Value = null; 94 } 95 } 96 97 [StorableConstructor] 98 private ResultParameter(bool deserializing) : base(deserializing) { } 99 private ResultParameter(ResultParameter<T> original, Cloner cloner) 100 : base(original, cloner) { 101 resultName = original.resultName; 102 resultCollectionName = original.resultCollectionName; 103 defaultValue = cloner.Clone(original.defaultValue); 104 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 105 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 106 } 107 public override IDeepCloneable Clone(Cloner cloner) { 108 return new ResultParameter<T>(this, cloner); 109 } 110 public ResultParameter() : this("Anonymous") { } 111 public ResultParameter(string name) 112 : base(name, typeof(T)) { 113 resultName = Name; 114 resultCollectionName = "Results"; 115 defaultValue = new T(); 116 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 117 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 118 } 119 public ResultParameter(string name, string description) : this(name, description, new T()) { } 120 public ResultParameter(string name, string description, T defaultValue) 121 : base(name, description, typeof(T)) { 122 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 123 resultName = Name; 124 resultCollectionName = "Results"; 125 this.defaultValue = defaultValue; 126 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 127 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 128 } 129 public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { } 130 public ResultParameter(string name, string description, T defaultValue, string resultName) 131 : base(name, description, typeof(T)) { 132 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 133 this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName; 134 resultCollectionName = "Results"; 135 this.defaultValue = defaultValue; 136 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 137 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 138 } 139 public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { } 140 public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName) 141 : base(name, description, typeof(T)) { 142 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 143 this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName; 144 this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName; 145 this.defaultValue = defaultValue; 146 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 147 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 148 } 149 150 public override string ToString() { 151 if (Name.Equals(ResultName)) return Name; 152 return Name + ": " + ResultName; 153 } 154 155 156 private ResultCollection LookupResultCollection() { 157 var scope = ExecutionContext.Scope; 158 while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName) 159 && !(scope.Variables[ResultCollectionName].Value is ResultCollection)) 160 scope = scope.Parent; 161 return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null; 162 } 163 164 protected override IItem GetActualValue() { 165 if (CachedActualValue != null) return CachedActualValue; 166 167 var results = LookupResultCollection(); 168 if (results == null) 169 throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found."); 170 171 if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone())); 172 var resultValue = results[ResultName].Value; 173 if (!(resultValue is T)) 174 throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName())); 175 176 cachedActualValues.Value.Value = resultValue; 177 return resultValue; 178 } 179 180 protected override void SetActualValue(IItem value) { 181 if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName())); 182 183 var results = LookupResultCollection(); 184 if (results == null) 185 throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found."); 186 187 if (!results.ContainsKey(ResultName)) 188 results.Add(new Result(ResultName, value)); 189 else results[ResultName].Value = value; 190 191 cachedActualValues.Value.Value = value; 192 } 193 194 public event EventHandler ResultNameChanged; 195 private void OnResultNameChanged() { 196 var handler = ResultNameChanged; 197 if (handler != null) handler(this, EventArgs.Empty); 198 OnToStringChanged(); 199 } 200 201 public event EventHandler ResultCollectionNameChanged; 202 private void OnResultCollectionNameChanged() { 203 var handler = ResultCollectionNameChanged; 204 if (handler != null) handler(this, EventArgs.Empty); 205 } 206 207 public event EventHandler DefaultValueChanged; 208 private void OnDefaultValueChanged() { 209 EventHandler handler = DefaultValueChanged; 210 if (handler != null) handler(this, EventArgs.Empty); 211 OnItemImageChanged(); 212 } 213 214 #region IStatefulItem members 215 public void InitializeState() { 216 } 217 218 public void ClearState() { 219 if (cachedActualValues.IsValueCreated) { 220 cachedActualValues.Value.Dispose(); 221 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 222 } 223 if (executionContexts.IsValueCreated) { 224 executionContexts.Value.Dispose(); 225 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 226 } 227 } 228 #endregion 229 } 230 } -
HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs
1 #region License Information 2 /* HeuristicLab 3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 * 5 * This file is part of HeuristicLab. 6 * 7 * HeuristicLab is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * HeuristicLab is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 #endregion 21 22 using System; 23 using System.Threading; 24 using HeuristicLab.Common; 25 using HeuristicLab.Core; 26 using HeuristicLab.Parameters; 27 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 28 29 namespace HeuristicLab.Optimization { 30 [Item("ResultParameter", "A parameter whose value is written to a result collection.")] 31 [StorableClass] 32 public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() { 33 34 [Storable] 35 private string resultName; 36 public string ResultName { 37 get { return resultName; } 38 set { 39 if (value == null) throw new ArgumentNullException(); 40 if (string.IsNullOrWhiteSpace(value)) { 41 resultName = Name; 42 OnResultNameChanged(); 43 } else if (!resultName.Equals(value)) { 44 resultName = value; 45 OnResultNameChanged(); 46 } 47 } 48 } 49 50 [Storable] 51 private string resultCollectionName; 52 public string ResultCollectionName { 53 get { return resultCollectionName; } 54 set { 55 if (value == null) throw new ArgumentNullException("value"); 56 if (string.IsNullOrWhiteSpace(value)) { 57 resultCollectionName = "Results"; 58 OnResultCollectionNameChanged(); 59 } else if (!resultCollectionName.Equals(value)) { 60 resultCollectionName = value; 61 OnResultCollectionNameChanged(); 62 } 63 } 64 } 65 66 [Storable] 67 private T defaultValue; 68 public T DefaultValue { 69 get { return defaultValue; } 70 set { 71 if (value != defaultValue) { 72 defaultValue = value; 73 OnDefaultValueChanged(); 74 } 75 } 76 } 77 78 public new T ActualValue { 79 get { return (T)base.ActualValue; } 80 set { base.ActualValue = value; } 81 } 82 83 private Lazy<ThreadLocal<IItem>> cachedActualValues; 84 private IItem CachedActualValue { 85 get { return cachedActualValues.Value.Value; } 86 } 87 88 private Lazy<ThreadLocal<IExecutionContext>> executionContexts; 89 public IExecutionContext ExecutionContext { 90 get { return executionContexts.Value.Value; } 91 set { 92 executionContexts.Value.Value = value; 93 cachedActualValues.Value.Value = null; 94 } 95 } 96 97 [StorableConstructor] 98 private ResultParameter(bool deserializing) : base(deserializing) { } 99 private ResultParameter(ResultParameter<T> original, Cloner cloner) 100 : base(original, cloner) { 101 resultName = original.resultName; 102 resultCollectionName = original.resultCollectionName; 103 defaultValue = cloner.Clone(original.defaultValue); 104 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 105 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 106 } 107 public override IDeepCloneable Clone(Cloner cloner) { 108 return new ResultParameter<T>(this, cloner); 109 } 110 public ResultParameter() : this("Anonymous") { } 111 public ResultParameter(string name) 112 : base(name, typeof(T)) { 113 resultName = Name; 114 resultCollectionName = "Results"; 115 defaultValue = new T(); 116 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 117 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 118 } 119 public ResultParameter(string name, string description) : this(name, description, new T()) { } 120 public ResultParameter(string name, string description, T defaultValue) 121 : base(name, description, typeof(T)) { 122 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 123 resultName = Name; 124 resultCollectionName = "Results"; 125 this.defaultValue = defaultValue; 126 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 127 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 128 } 129 public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { } 130 public ResultParameter(string name, string description, T defaultValue, string resultName) 131 : base(name, description, typeof(T)) { 132 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 133 this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName; 134 resultCollectionName = "Results"; 135 this.defaultValue = defaultValue; 136 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 137 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 138 } 139 public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { } 140 public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName) 141 : base(name, description, typeof(T)) { 142 if (defaultValue == null) throw new ArgumentNullException("defaultValue"); 143 this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName; 144 this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName; 145 this.defaultValue = defaultValue; 146 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 147 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 148 } 149 150 public override string ToString() { 151 if (Name.Equals(ResultName)) return Name; 152 return Name + ": " + ResultName; 153 } 154 155 156 private ResultCollection LookupResultCollection() { 157 var scope = ExecutionContext.Scope; 158 while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName) 159 && !(scope.Variables[ResultCollectionName].Value is ResultCollection)) 160 scope = scope.Parent; 161 return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null; 162 } 163 164 protected override IItem GetActualValue() { 165 if (CachedActualValue != null) return CachedActualValue; 166 167 var results = LookupResultCollection(); 168 if (results == null) 169 throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found."); 170 171 if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone())); 172 var resultValue = results[ResultName].Value; 173 if (!(resultValue is T)) 174 throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName())); 175 176 cachedActualValues.Value.Value = resultValue; 177 return resultValue; 178 } 179 180 protected override void SetActualValue(IItem value) { 181 if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName())); 182 183 var results = LookupResultCollection(); 184 if (results == null) 185 throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found."); 186 187 if (!results.ContainsKey(ResultName)) 188 results.Add(new Result(ResultName, value)); 189 else results[ResultName].Value = value; 190 191 cachedActualValues.Value.Value = value; 192 } 193 194 public event EventHandler ResultNameChanged; 195 private void OnResultNameChanged() { 196 var handler = ResultNameChanged; 197 if (handler != null) handler(this, EventArgs.Empty); 198 OnToStringChanged(); 199 } 200 201 public event EventHandler ResultCollectionNameChanged; 202 private void OnResultCollectionNameChanged() { 203 var handler = ResultCollectionNameChanged; 204 if (handler != null) handler(this, EventArgs.Empty); 205 } 206 207 public event EventHandler DefaultValueChanged; 208 private void OnDefaultValueChanged() { 209 EventHandler handler = DefaultValueChanged; 210 if (handler != null) handler(this, EventArgs.Empty); 211 OnItemImageChanged(); 212 } 213 214 #region IStatefulItem members 215 public void InitializeState() { 216 } 217 218 public void ClearState() { 219 if (cachedActualValues.IsValueCreated) { 220 cachedActualValues.Value.Dispose(); 221 cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 222 } 223 if (executionContexts.IsValueCreated) { 224 executionContexts.Value.Dispose(); 225 executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication); 226 } 227 } 228 #endregion 229 } 230 }