Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CloningRefactorBranch/HeuristicLab.Operators.Programmable/ProgrammableOperator.cs @ 887

Last change on this file since 887 was 887, checked in by gkronber, 15 years ago

Refactored cloning in all plugins except: HL.Communication, HL.Hive, HL.GP, HL.Routing, HL.Scheduling, HL.SimOpt, HL.Visualization

#285 (Cloning could be improved by creating objects at the bottom of the cloning chain with 'new' instead of the top with Activator.CreateInstance())

File size: 9.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Xml;
26using System.IO;
27using System.Linq;
28using System.Reflection;
29using System.CodeDom;
30using System.CodeDom.Compiler;
31using Microsoft.CSharp;
32using System.Text.RegularExpressions;
33using HeuristicLab.Core;
34using HeuristicLab.Data;
35using System.Data.Linq;
36
37namespace HeuristicLab.Operators.Programmable {
38  public class ProgrammableOperator : OperatorBase {
39    private MethodInfo executeMethod;
40
41    private string myDescription;
42    public override string Description {
43      get { return myDescription; }
44    }
45    private string myCode;
46    public string Code {
47      get { return myCode; }
48      set {
49        if (value != myCode) {
50          myCode = value;
51          executeMethod = null;
52          OnCodeChanged();
53        }
54      }
55    }
56
57    /// <summary>
58    /// Default constructor.
59    /// </summary>
60    public ProgrammableOperator() {
61      myCode = "Result.Data = true;";
62      myDescription = "An operator that can be programmed for arbitrary needs.";
63      AddVariableInfo(new VariableInfo("Result", "A computed variable", typeof(BoolData), VariableKind.New | VariableKind.Out));
64      executeMethod = null;
65    }
66
67
68    /// <summary>
69    /// Copy constructor to create deep clones.
70    /// </summary>
71    /// <param name="original">The instance to be cloned.</param>
72    public ProgrammableOperator(ProgrammableOperator original) : this(original, new Dictionary<Guid, object>()) { }
73    /// <summary>
74    /// Copy constructor to create a deep clone of an ProgrammableOperator instance.
75    /// </summary>
76    /// <param name="original">The original instance to be cloned.</param>
77    /// <param name="clonedObjects">Already cloned object references.</param>
78    protected ProgrammableOperator(ProgrammableOperator original, IDictionary<Guid, object> clonedObjects)
79      : base(original, clonedObjects) {
80      this.myDescription = original.Description;
81      this.myCode = original.Code;
82      this.executeMethod = original.executeMethod;
83    }
84
85    public void SetDescription(string description) {
86      if (description == null)
87        throw new NullReferenceException("description must not be null");
88
89      if (description != myDescription) {
90        myDescription = description;
91        OnDescriptionChanged();
92      }
93    }
94
95    public virtual void Compile() {
96      CodeNamespace ns = new CodeNamespace("HeuristicLab.Operators.Programmable.CustomOperators");
97      CodeTypeDeclaration typeDecl = new CodeTypeDeclaration("Operator");
98      typeDecl.IsClass = true;
99      typeDecl.TypeAttributes = TypeAttributes.Public;
100
101      CodeMemberMethod method = new CodeMemberMethod();
102      method.Name = "Execute";
103      method.ReturnType = new CodeTypeReference(typeof(IOperation));
104      method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
105      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IOperator), "op"));
106      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IScope), "scope"));
107      foreach (IVariableInfo info in VariableInfos)
108        method.Parameters.Add(new CodeParameterDeclarationExpression(info.DataType, info.FormalName));
109      string code = myCode + "\r\n" + "return null;";
110      method.Statements.Add(new CodeSnippetStatement(code));
111      typeDecl.Members.Add(method);
112
113      ns.Types.Add(typeDecl);
114      ns.Imports.Add(new CodeNamespaceImport("System"));
115      ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
116      ns.Imports.Add(new CodeNamespaceImport("System.Text"));
117      ns.Imports.Add(new CodeNamespaceImport("System.Linq"));
118      ns.Imports.Add(new CodeNamespaceImport("System.Data.Linq"));
119      ns.Imports.Add(new CodeNamespaceImport("HeuristicLab.Core"));
120      foreach (IVariableInfo variableInfo in VariableInfos)
121        ns.Imports.Add(new CodeNamespaceImport(variableInfo.DataType.Namespace));
122
123      CodeCompileUnit unit = new CodeCompileUnit();
124      unit.Namespaces.Add(ns);
125      CompilerParameters parameters = new CompilerParameters();
126      parameters.GenerateExecutable = false;
127      parameters.GenerateInMemory = true;
128      parameters.IncludeDebugInformation = false;
129      Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
130      foreach (Assembly loadedAssembly in loadedAssemblies)
131        parameters.ReferencedAssemblies.Add(loadedAssembly.Location);
132      parameters.ReferencedAssemblies.Add(typeof(Enumerable).Assembly.Location); // add reference to version 3.5 of System.dll
133      parameters.ReferencedAssemblies.Add(typeof(DataContext).Assembly.Location); // add reference System.Data.Linq.Dll
134      CodeDomProvider provider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });  // support C# 3.0 syntax
135      CompilerResults results = provider.CompileAssemblyFromDom(parameters, unit);
136
137      executeMethod = null;
138      if (results.Errors.HasErrors) {
139        StringWriter writer = new StringWriter();
140        CodeGeneratorOptions options = new CodeGeneratorOptions();
141        options.BlankLinesBetweenMembers = false;
142        options.ElseOnClosing = true;
143        options.IndentString = "  ";
144        provider.GenerateCodeFromCompileUnit(unit, writer, options);
145        writer.Flush();
146        string[] source = writer.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
147        StringBuilder builder = new StringBuilder();
148        for (int i = 0; i < source.Length; i++)
149          builder.AppendLine((i + 1).ToString("###") + "     " + source[i]);
150        builder.AppendLine();
151        builder.AppendLine();
152        builder.AppendLine();
153        foreach (CompilerError error in results.Errors) {
154          builder.Append("Line " + error.Line.ToString());
155          builder.Append(", Column " + error.Column.ToString());
156          builder.AppendLine(": " + error.ErrorText);
157        }
158        throw new Exception("Compile Errors:\n\n" + builder.ToString());
159      } else {
160        Assembly assembly = results.CompiledAssembly;
161        Type[] types = assembly.GetTypes();
162        executeMethod = types[0].GetMethod("Execute");
163      }
164    }
165
166    public override IOperation Apply(IScope scope) {
167      if (executeMethod == null) {
168        Compile();
169      }
170
171      // collect parameters
172      object[] parameters = new object[VariableInfos.Count + 2];
173      parameters[0] = this;
174      parameters[1] = scope;
175      int i = 2;
176      foreach (IVariableInfo info in VariableInfos) {
177        if ((info.Kind & VariableKind.New) == VariableKind.New) {
178          parameters[i] = GetVariableValue(info.FormalName, scope, false, false);
179          if (parameters[i] == null) {
180            IItem value = (IItem)Activator.CreateInstance(info.DataType);
181            if (info.Local) {
182              AddVariable(new Variable(info.ActualName, value));
183            } else {
184              scope.AddVariable(new Variable(scope.TranslateName(info.FormalName), value));
185            }
186            parameters[i] = value;
187          }
188        } else
189          parameters[i] = GetVariableValue(info.FormalName, scope, true);
190        i++;
191      }
192
193      return (IOperation)executeMethod.Invoke(null, parameters);
194    }
195
196    public override IView CreateView() {
197      return new ProgrammableOperatorView(this);
198    }
199
200    public event EventHandler DescriptionChanged;
201    protected virtual void OnDescriptionChanged() {
202      if (DescriptionChanged != null)
203        DescriptionChanged(this, new EventArgs());
204    }
205    public event EventHandler CodeChanged;
206    protected virtual void OnCodeChanged() {
207      if (CodeChanged != null)
208        CodeChanged(this, new EventArgs());
209    }
210
211
212    /// <summary>
213    /// Creates a deep clone with the copy constructor reusing already cloned
214    /// object references.
215    /// </summary>
216    /// <param name="clonedObjects">Already cloned objects (for referential integrity).</param>
217    /// <returns>The cloned instance.</returns>
218    public override object Clone(IDictionary<Guid, object> clonedObjects) {
219      return new ProgrammableOperator(this, clonedObjects);
220    }
221    #region Persistence Methods
222    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
223      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
224      XmlNode descriptionNode = document.CreateNode(XmlNodeType.Element, "Description", null);
225      descriptionNode.InnerText = myDescription;
226      node.AppendChild(descriptionNode);
227      XmlNode codeNode = document.CreateNode(XmlNodeType.Element, "Code", null);
228      codeNode.InnerText = myCode;
229      node.AppendChild(codeNode);
230      return node;
231    }
232    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
233      base.Populate(node, restoredObjects);
234      XmlNode descriptionNode = node.SelectSingleNode("Description");
235      myDescription = descriptionNode.InnerText;
236      XmlNode codeNode = node.SelectSingleNode("Code");
237      myCode = codeNode.InnerText;
238    }
239    #endregion
240  }
241}
Note: See TracBrowser for help on using the repository browser.