2016-05-17 39 views
1

我已經簡化了很多以達到問題的核心:評估代碼內聯(或使用反射)

我有一個需要填充屬性的控件。不幸的是,這些值都在CodeDom.CodeStatements中。

所以我真的有使用這樣的代碼來撈取值:

static string GenerateCode(CodeStatementCollection statements, Control control) 
     { 
     var writer = new StringWriter(); 

     var compiler = new CSharpCodeProvider(); 

     foreach (CodeStatement statement in statements) 
     { 
      var codeAssignStatement = statement as System.CodeDom.CodeAssignStatement; 

      var left = codeAssignStatement?.Left as System.CodeDom.CodePropertyReferenceExpression; 

      if (left == null) 
      { 
       continue; 
      } 

      var right = codeAssignStatement.Right as System.CodeDom.CodeObjectCreateExpression; 

      if (right == null) 
      { 
       continue; 
      } 

      var expressionWriter = new StringWriter(); 
      compiler.GenerateCodeFromExpression(right,expressionWriter,null); 
      var expression = expressionWriter.ToString(); 

      control.SetPropertyValue(left.PropertyName, expression); 

      compiler.GenerateCodeFromStatement(statement, writer, null); 

     } 

     return writer.ToString(); 
     } 

請注意,該代碼是使用反射,SetPropertyValue實際上是一個擴展方法:

public static void SetPropertyValue(this object obj, string propName, object value) 
     { 
     obj.GetType().GetProperty(propName).SetValue(obj, value, null); 
     } 

但這隻有在值是文字值時纔有效,而不是表達式。

在運行時,正是我從CodeDOM的聲明得到的是一種表達,也是控制是一個按鈕。

Button.Location = New System.Drawing.Point(12,12);

所以上面的代碼示例中,表達=「新System.Drawing.Point(12,12)」

現在我不希望有通過一系列的運行IF語句第一確定類型。

是否有可能使用反射來設置基於表達式的屬性?

如果沒有,是否有可能使用某種eval函數在.NET拉這一關?

回答

2

要從腳本創建代碼,您需要動態編譯該方法。

你必須做的第一件事是編譯方法爲MethodInfo。 您可以創建一個方法來完成此操作。

public static MethodInfo CreateMethodInfo(string script, string className, string methodName) 
{ 
    using (var compiler = new CSharpCodeProvider()) 
    { 
     var parms = new CompilerParameters 
     { 
      GenerateExecutable = false, 
      GenerateInMemory = true, 
      ReferencedAssemblies = { "System.Drawing.dll" } 
     }; 
     return compiler.CompileAssemblyFromSource(parms, script) 
      .CompiledAssembly.GetType(className) 
      .GetMethod(methodName); 
    } 
} 

一旦你完成了這個工作,你可以像這樣使用它。

var script = "public class Methods{public static System.Drawing.Point DoSomething(){return new System.Drawing.Point(12, 12);}}"; 

var method = CreateMethodInfo(script, "Methods", "DoSomething"); 

現在method變量保存您的MethodInfo,所以你只需要調用它。

Button.Location = (Point)method.Invoke(null, null); 
+0

你真聰明!這工作完美。非常感謝你! –

0

我想你可以嘗試LINQ表達式。 https://msdn.microsoft.com/en-us/library/bb335710(v=vs.110).aspx

改變你的方法如下所示:

public static void SetPropertyValue(this object obj, string propName, Expression<Func<T, object>> value) 

配置和編譯委託函數表達式,並調用它在你的SetPropertyValue()。