在.Net中反射执行代码

问题描述:

您如何反思性地或动态地在.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

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切换),对于动态代码非常有用。

尽管我不建议您采用任何方法,但您可以使用Reflection.Emit完成您想要的任务。这是a tutorial

您是否会更好地定义一组可能的常量,然后您可以在代码中对其进行解析并动态执行,而不仅仅是通过任何C#代码。

它看起来像你需要某种基本的规则处理器。有几个选项可以完成你所需要的。像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

它提供了一个动态的表达式解析器,其中,虽然它不完全支持你在有表情你的问题,几乎支持任何其他基本表达。

你真的想让任何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> 

,你首先需要创建和存储编译你的代码的类在里面,后它已被编译,您需要反思它并调用您的动态代码所在的方法,方法也可以返回值。

这里是一个链接,让你开始Dynamic Code

取决于你想要做什么,你可能会发现,从春季.NET一些组件是有用的。看看Spring .NET Expressions

例如:

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

,其中 “新的DateTime(1974,8,24)” 是你的文字

如果您不需要C#语法到最后一个逗号,最简单的这样做的方式可能是通过使用像IronPython这样的DLR语言。谷歌为“托管蟒蛇”,你会发现样本。