#region License Information /* HeuristicLab * Copyright (C) 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 . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HEAL.Attic; namespace HeuristicLab.Parameters { /// /// A generic parameter representing instances of type T which are collected from or written to scope tree. /// [Item("ScopeTreeLookupParameter", "A generic parameter representing instances of type T which are collected from or written to scope tree.")] [StorableType("51F36637-C22C-4CDC-B34B-F49CA7896E35")] public class ScopeTreeLookupParameter : LookupParameter>, IScopeTreeLookupParameter where T : class, IItem { [Storable] private int depth; public int Depth { get { return depth; } set { if (value < 0) throw new ArgumentException("Depth must be larger than or equal to 0."); if (depth != value) { depth = value; OnDepthChanged(); } } } [StorableConstructor] protected ScopeTreeLookupParameter(StorableConstructorFlag _) : base(_) { } protected ScopeTreeLookupParameter(ScopeTreeLookupParameter original, Cloner cloner) : base(original, cloner) { depth = original.depth; } public ScopeTreeLookupParameter() : base() { depth = 1; } public ScopeTreeLookupParameter(string name) : base(name) { depth = 1; } public ScopeTreeLookupParameter(string name, int depth) : base(name) { this.depth = depth; } public ScopeTreeLookupParameter(string name, string description) : base(name, description) { depth = 1; } public ScopeTreeLookupParameter(string name, string description, int depth) : base(name, description) { this.depth = depth; } public ScopeTreeLookupParameter(string name, string description, string actualName) : base(name, description, actualName) { depth = 1; } public ScopeTreeLookupParameter(string name, string description, string actualName, int depth) : base(name, description, actualName) { this.depth = depth; } public override IDeepCloneable Clone(Cloner cloner) { return new ScopeTreeLookupParameter(this, cloner); } protected override IItem GetActualValue() { IEnumerable scopes = new IScope[] { ExecutionContext.Scope }; for (int i = 0; i < depth; i++) scopes = scopes.Select(x => (IEnumerable)x.SubScopes).Aggregate((a, b) => a.Concat(b)); string name = TranslatedName; List values = new List(); IVariable var; T value; foreach (IScope scope in scopes) { scope.Variables.TryGetValue(name, out var); if (var != null) { value = var.Value as T; if ((var.Value != null) && (value == null)) throw new InvalidOperationException( string.Format("Type mismatch. Variable \"{0}\" does not contain a \"{1}\".", name, typeof(T).GetPrettyName()) ); values.Add(value); } } return new ItemArray(values); } protected override void SetActualValue(IItem value) { ItemArray values = value as ItemArray; if (values == null) throw new InvalidOperationException( string.Format("Type mismatch. Value is not a \"{0}\".", typeof(ItemArray).GetPrettyName()) ); IEnumerable scopes = new IScope[] { ExecutionContext.Scope }; for (int i = 0; i < depth; i++) scopes = scopes.Select(x => (IEnumerable)x.SubScopes).Aggregate((a, b) => a.Concat(b)); if (scopes.Count() != values.Length) throw new InvalidOperationException("Number of values is not equal to number of scopes."); string name = TranslatedName; int j = 0; IVariable var; foreach (IScope scope in scopes) { scope.Variables.TryGetValue(name, out var); if (var != null) var.Value = values[j]; else scope.Variables.Add(new Variable(name, values[j])); j++; } } public event EventHandler DepthChanged; protected virtual void OnDepthChanged() { EventHandler handler = DepthChanged; if (handler != null) handler(this, EventArgs.Empty); } } }