2009-06-11 47 views
2

您如何反思性地或動態地在.Net中執行代碼?如果XML包含內在的東西「[]」我要處理的文本而不是文字而是代碼:在.Net中反射執行代碼

<Name>DateZero</Name>
<Value>DateTime.Now.AddDays(-2)</Value>

<Name>DateOne</Name>
<Value>[DateTime.Now.AddDays(-1).ToString("MM/dd/yy")]</Value>

<Name>DateTwo</Name>
<Value>[DateTime.Now.ToString("MM/dd/yy")]</Value>

意味着對於DateZero值將呈現爲「DateTime.Now.AddDays(-2 )「,但對於接下來的兩個,它將呈現爲06/10/09和06/11/09。

+0

你真的想允許任何C#代碼嗎?看起來像一個巨大的安全漏洞。 – Cheeso 2009-06-11 16:03:49

回答

2

CS-Script會做你想要的。

從自己的一個例子:

Assembly assembly = CSScript.LoadMethod(
     @"public static void PrintSum(int a, int b) 
      { 
       Console.WriteLine((a+b)); 
      }"); 

AsmHelper script = new AsmHelper(assembly); 
script.Invoke("*.PrintSum", 1, 2); 

這應該是很容易做你想要什麼。我將它用於我們的規則引擎(剛剛從Boo切換),對於動態代碼非常有用。

1

儘管我不建議您採用任何方法,但您可以使用Reflection.Emit完成您想要的任務。這是a tutorial

1

您是否會更好地定義一組可能的常量,然後您可以在代碼中對其進行解析並動態執行,而不僅僅是通過任何C#代碼。

2

它看起來像你需要某種基本的規則處理器。有幾個選項可以完成你所需要的。像Randolpho提到的那樣,您可以使用Reflection.Emit在運行時生成輕量級IL代碼。另一種選擇是,如果你有.NET 3.5,則使用表達式樹。

隨着LINQ的推出,微軟需要在.NET中添加一個基本的表達式引擎,以便在編譯過程中可以將LINQ語句轉換爲。然而,表達式庫不僅限於支持LINQ,而且您應該能夠編寫一個基本的分析器,將您的XML轉換爲表達式樹。每個表達式樹可以稍後編譯成一個委託,然後可以同步或異步調用該委託。

你可能會發現,如果你做探索表達式樹航線以​​下鏈接有用:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

它提供了一個動態的表達式解析器,其中,雖然它不完全支持你在有表情你的問題,幾乎支持任何其他基本表達。

1

你真的想讓任何C#嗎?
如果是這樣,你可能想看看this script engine for C#。請記住,能夠運行任意代碼是一個巨大的安全風險。

如果您在等待.NET 4.0(現在測試版,今年晚些時候發佈)時可以使用,那麼您可以使用DLR或動態語言運行庫來實現此目的。另一方面,如果你不想依賴.NET 4.0,並且你願意限制自己,那麼你可以很簡單地使用Reflection。 如果你可以限制自己,例如,在DateTime實例上的方法,事情會更簡單。此示例顯示如何通過反射調用一個設置爲NOW的DateTime實例。

DateTime d = DateTime.Now; 
    string logicToInvoke= "Now.AddDays(12)"; 
    string pattern = @"^Now\.(?<methodname>\w+)\((?<argstring>[^\)]*)\)"; 
    RGX.Match match = RGX.Regex.Match(logicToInvoke, pattern); 

    // If match not found, logic is improperly formed. 
    if (!match.Success) 
    { 
     Console.WriteLine("The DateTime method logic is improperly formed."); 
     return; 
    } 

    // Store method and arg 
    string methodName = (string) match.Groups["methodname"].Value; 
    string argString = (string) match.Groups["argstring"].Value; 

    Console.WriteLine("Invoking method '{0}' with args '{1}'...", methodName, argString); 
    System.Type t= d.GetType(); 

    try 
    { 
     switch (methodName) 
     { 

     case "AddDays" : 
      int daysToAdd = System.Int32.Parse(argString); 
      DateTime result = (DateTime) t.InvokeMember (methodName, 
              System.Reflection.BindingFlags.Public | 
              System.Reflection.BindingFlags.Instance | 
              System.Reflection.BindingFlags.InvokeMethod , 
              null, d, new object [] {daysToAdd}); 

      Console.WriteLine("Result: {0}", result.ToString("yyyy/MM/dd")); 
      break; 
     default: 
      Console.WriteLine("unsupported method: {0}", methodName); 
      break; 
     } 

    } 
    catch (System.Exception exc1) 
    { 
     Console.WriteLine("Exception while invoking method: {0}", exc1); 
    } 

我建議保持DateTime值的格式與它的值分開。的時間(「YY/MM/DD」)的格式可能在屬性中更好的指定,與:

<Name>DateOne</Name> 
<Value format="MM/dd/yy">[Now.AddDays(-1)]</Value> 
0

,你首先需要創建和存儲編譯你的代碼的類在裏面,後它已被編譯,您需要反思它並調用您的動態代碼所在的方法,方法也可以返回值。

這裏是一個鏈接,讓你開始Dynamic Code

0

取決於你想要做什麼,你可能會發現,從春季.NET一些組件是有用的。看看Spring .NET Expressions

例如:

(DateTime) ExpressionEvaluator.GetValue(null, "new DateTime(1974, 8, 24)")

,其中 「新的DateTime(1974,8,24)」 是你的文字

0

如果您不需要C#語法到最後一個逗號,最簡單的這樣做的方式可能是通過使用像IronPython這樣的DLR語言。谷歌爲「託管蟒蛇」,你會發現樣本。