首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C# 4.0中执行字符串

问在C# 4.0中执行字符串
EN

Stack Overflow用户
提问于 2009-04-17 11:43:33
回答 6查看 12.6K关注 0票数 7

我想在C#中执行动态创建的字符串。我知道VB和JScript.Net可以做到这一点,甚至有一个way可以使用它在C#中的程序集作为变通办法。我还找到了这个描述如何做的article。

我今天读到了关于C# 4.0的特性,这些特性使它更接近于将其作为主要特性之一的动态语言。那么,有没有人知道C# 4.0包括一些内置的特性,允许字符串执行,或者任何其他方式来做上面文章中描述的事情。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2009-04-17 11:47:57

除了将其编译成程序集然后执行之外,没有其他方法可以执行任意C#源代码。Anders Hejlsberg ( C#的架构师)宣布了将C#编译器公开为服务(基本上是一组CLR类)的计划,因此当这种情况发生时,这可能会有所帮助。

"Compiler as a Service“基本上意味着您可以将任意一段代码编译成表达式,或者更好的是,编译成AST,并且通常可以掌握内部编译器的工作方式。

票数 11
EN

Stack Overflow用户

发布于 2009-04-17 13:42:11

这是非常容易做到的。我构建了以下方便的包装器。它们是结构化的,因此您可以从定义方法或表达式的源代码片段构造程序集,并使用DynamicCodeManager的帮助器方法按名称调用它们。

代码按需编译,以响应调用。添加更多方法将导致下次调用时自动重新编译。

您只提供了一个方法体。如果您不想返回值,那么返回null,并且不必费心使用InvokeMethod返回的对象。

如果您在商业代码中使用它,请帮我一个忙,并信任我的工作。这个库中真正的宝石是对调用的支持。让代码编译不是问题,而是调用。当你有一个可变长度的参数列表时,让反射正确匹配方法签名是相当棘手的。这就是DynamicBase存在的原因:编译器将方法绑定解析到这个显式声明的基类,使我们能够访问正确的VMT。从那时起,所有的一切都会在洗礼中被淘汰。

我还应该指出,此功能使您的桌面应用程序容易受到脚本注入攻击。您应该非常小心地检查脚本的来源,或者降低运行生成的程序集时所使用的信任级别。

DynamicBase.cs

代码语言:javascript
复制
using System.Reflection;

namespace Dynamo
{
  public abstract class DynamicBase
  {
    public bool EvaluateCondition(string methodName, params object[] p)
    {
      methodName = string.Format("__dm_{0}", methodName);
      BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic;
      return (bool)GetType().InvokeMember(methodName, flags, null, this, p);
    }
    public object InvokeMethod(string methodName, params object[] p)
    {
      BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic;
      return GetType().InvokeMember(methodName, flags, null, this, p);
    }
    public double Transform(string functionName, params object[] p)
    {
      functionName = string.Format("__dm_{0}", functionName);
      BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic;
      return (double)GetType().InvokeMember(functionName, flags, null, this, p);
    }
  }
}

DynamicCodeManager.cs

代码语言:javascript
复制
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;

namespace Dynamo
{
  public static class DynamicCodeManager
  {
    #region internal statics and constants
    static Dictionary<string, string> _conditionSnippet = new Dictionary<string, string>();
    static Dictionary<string, string> _methodSnippet = new Dictionary<string, string>();
    static string CodeStart = "using System;\r\nusing System.Collections.Generic;\r\n//using System.Linq;\r\nusing System.Text;\r\nusing System.Data;\r\nusing System.Reflection;\r\nusing System.CodeDom.Compiler;\r\nusing Microsoft.CSharp;\r\nnamespace Dynamo\r\n{\r\n  public class Dynamic : DynamicBase\r\n  {\r\n";
    static string DynamicConditionPrefix = "__dm_";
    static string ConditionTemplate = "    bool {0}{1}(params object[] p) {{ return {2}; }}\r\n";
    static string MethodTemplate = "    object {0}(params object[] p) {{\r\n{1}\r\n    }}\r\n";
    static string CodeEnd = "  }\r\n}";
    static List<string> _references = new List<string>("System.dll,System.dll,System.Data.dll,System.Xml.dll,mscorlib.dll,System.Windows.Forms.dll".Split(new char[] { ',' }));
    static Assembly _assembly = null;
    #endregion

    public static Assembly Assembly { get { return DynamicCodeManager._assembly; } }

    #region manage snippets
    public static void Clear()
    {
      _methodSnippet.Clear();
      _conditionSnippet.Clear();
      _assembly = null;
    }
    public static void Clear(string name)
    {
      if (_conditionSnippet.ContainsKey(name))
      {
        _assembly = null;
        _conditionSnippet.Remove(name);
      }
      else if (_methodSnippet.ContainsKey(name))
      {
        _assembly = null;
        _methodSnippet.Remove(name);
      }
    }

    public static void AddCondition(string conditionName, string booleanExpression)
    {
      if (_conditionSnippet.ContainsKey(conditionName))
        throw new InvalidOperationException(string.Format("There is already a condition called '{0}'", conditionName));
      StringBuilder src = new StringBuilder(CodeStart);
      src.AppendFormat(ConditionTemplate, DynamicConditionPrefix, conditionName, booleanExpression);
      src.Append(CodeEnd);
      Compile(src.ToString()); //if the condition is invalid an exception will occur here
      _conditionSnippet[conditionName] = booleanExpression;
      _assembly = null;
    }

    public static void AddMethod(string methodName, string methodSource)
    {
      if (_methodSnippet.ContainsKey(methodName))
        throw new InvalidOperationException(string.Format("There is already a method called '{0}'", methodName));
      if (methodName.StartsWith(DynamicConditionPrefix))
        throw new InvalidOperationException(string.Format("'{0}' is not a valid method name because the '{1}' prefix is reserved for internal use with conditions", methodName, DynamicConditionPrefix));
      StringBuilder src = new StringBuilder(CodeStart);
      src.AppendFormat(MethodTemplate, methodName, methodSource);
      src.Append(CodeEnd);
      Trace.TraceError("SOURCE\r\n{0}", src);
      Compile(src.ToString()); //if the condition is invalid an exception will occur here
      _methodSnippet[methodName] = methodSource;
      _assembly = null;
    }
    #endregion

    #region use snippets
    public static object InvokeMethod(string methodName, params object[] p)
    {
      DynamicBase _dynamicMethod = null;
      if (_assembly == null)
      {
        Compile();
        _dynamicMethod = _assembly.CreateInstance("Dynamo.Dynamic") as DynamicBase;
      }
      return _dynamicMethod.InvokeMethod(methodName, p);
    }

    public static bool Evaluate(string conditionName, params object[] p)
    {
      DynamicBase _dynamicCondition = null;
      if (_assembly == null)
      {
        Compile();
        _dynamicCondition = _assembly.CreateInstance("Dynamo.Dynamic") as DynamicBase;
      }
      return _dynamicCondition.EvaluateCondition(conditionName, p);
    }

    public static double Transform(string functionName, params object[] p)
    {
      DynamicBase _dynamicCondition = null;
      if (_assembly == null)
      {
        Compile();
        _dynamicCondition = _assembly.CreateInstance("Dynamo.Dynamic") as DynamicBase;
      }
      return _dynamicCondition.Transform(functionName, p);
    }
    #endregion

    #region support routines
    public static string ProduceConditionName(Guid conditionId)
    {
      StringBuilder cn = new StringBuilder();
      foreach (char c in conditionId.ToString().ToCharArray()) if (char.IsLetterOrDigit(c)) cn.Append(c);
      string conditionName = cn.ToString();
      return string.Format("_dm_{0}",cn);
    }
    private static void Compile()
    {
      if (_assembly == null)
      {
        StringBuilder src = new StringBuilder(CodeStart);
        foreach (KeyValuePair<string, string> kvp in _conditionSnippet)
          src.AppendFormat(ConditionTemplate, DynamicConditionPrefix, kvp.Key, kvp.Value);
        foreach (KeyValuePair<string, string> kvp in _methodSnippet)
          src.AppendFormat(MethodTemplate, kvp.Key, kvp.Value);
        src.Append(CodeEnd);
        Trace.TraceError("SOURCE\r\n{0}", src);
        _assembly = Compile(src.ToString());
      }
    }
    private static Assembly Compile(string sourceCode)
    {
      CompilerParameters cp = new CompilerParameters();
      cp.ReferencedAssemblies.AddRange(_references.ToArray());
      cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName);
      cp.CompilerOptions = "/target:library /optimize";
      cp.GenerateExecutable = false;
      cp.GenerateInMemory = true;
      CompilerResults cr = (new CSharpCodeProvider()).CompileAssemblyFromSource(cp, sourceCode);
      if (cr.Errors.Count > 0) throw new CompilerException(cr.Errors);
      return cr.CompiledAssembly;
    }
    #endregion

    public static bool HasItem(string methodName)
    {
      return _conditionSnippet.ContainsKey(methodName) || _methodSnippet.ContainsKey(methodName);
    }
  }
}
票数 13
EN

Stack Overflow用户

发布于 2009-04-17 11:48:38

目前,在MS .NET实现中,CSharpCodeProvider (在您引用的文章中)是唯一的方法。“编译器即服务”是.NET vFuture的一项功能,它提供了您所需要的功能。Mono 2.x已经有了类似的东西,IIRC (as discussed here)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/760088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档