在项目进行中有时候会需要配置一些复杂的表达式,在程序运行的时候执行表达式,根据结果执行相应的操作,简单写了一个类Expression,利用.net的动态编译技术实现,代码如下:

    public class Expression
{
/// <summary>
/// 执行一个表达式,或代码片段
/// </summary>
/// <param name="expression">表达式或代码片段</param>
/// <param name="parameters">表达式中的变量与实例的映射关系</param>
/// <returns>执行结果</returns>
public static object Eval(string expression, SortedDictionary<string, object> parameters = null)
{
try
{
parameters = parameters ?? new SortedDictionary<string, object>();
var objects = parameters.Values.ToList();
var types = objects.Select(x => x.GetType()).ToList();
var func = GetFunc(expression, parameters.Keys.ToList(), types); var funcTypes = types.ToList();
funcTypes.Add(typeof(object));
var type = Type.GetType("System.Func`" + funcTypes.Count); if (type == null) return null; type = type.MakeGenericType(funcTypes.ToArray()); var rst = type.InvokeMember("Invoke", BindingFlags.InvokeMethod, null, func, objects.ToArray());
return rst;
}
catch (Exception)
{
return null;
}
} private static object GetFunc(string expression, List<string> alias, List<Type> types)
{
string clsName = string.Format("Class{0}", Guid.NewGuid()).Replace("-", "_");
const string methodName = "ReturnFunc";
var strCode = CreateCode(clsName, methodName, expression, alias, types); CompilerResults result = Compile(strCode); Assembly assembly = result.CompiledAssembly;
Type aType = assembly.GetType(string.Format("NSName.{0}", clsName));
MethodInfo method = aType.GetMethod(methodName);
return method.Invoke(null, null);
} private static string CreateCode(string clsName, string methodName, string expression, List<string> alias, List<Type> types)
{
var ts = string.Empty;
if (types != null && types.Any())
{
ts = string.Join(",", types.Select(x => x.FullName)) + ",";
}
ts += "System.Object"; var strAlias = string.Format("({0})", string.Join(",", alias));
return @"
using System;
using System.Linq;
using System.Collections.Generic;
namespace NSName
{
internal static class " + clsName + @"
{
public static Func<" + ts + @"> " + methodName + @"()
{
return " + strAlias + @" => " + expression + @";
}
}
}";
} private static CompilerResults Compile(string code, List<string> assemblyPaths = null)
{
var provider = new CSharpCodeProvider();
var parameter = new CompilerParameters(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
assemblyPaths = assemblyPaths ?? new List<string>();
assemblyPaths.AddRange(assemblies.Where(x => !x.IsDynamic).Select(x => x.Location)); foreach (var assemblyPath in assemblyPaths)
{
if (!string.IsNullOrWhiteSpace(assemblyPath) && !parameter.ReferencedAssemblies.Contains(assemblyPath))
parameter.ReferencedAssemblies.Add(assemblyPath);
} parameter.GenerateExecutable = false;
parameter.GenerateInMemory = true; //将你的式子放在这里
CompilerResults result = provider.CompileAssemblyFromSource(parameter, code);
if (result.Errors.Count > )
{
var errorMsg = result.Errors.OfType<CompilerError>()
.Aggregate(string.Empty, (current, error) => current + error.ToString());
throw new Exception(errorMsg);
} return result;
}
}

测试准备代码:

public class Model1
{
public int X = ;
public int Y = ; public int Cal()
{
return X / Y;
}
} public class Model2
{
public int Z = ;
public bool B = false; public List<int> List = new List<int>
{
,,,,,,
};
} public class Model3
{
public Model3()
{
var s = string.Join(",",List);
}
public List<TObj> List = new List<TObj>
{
new TObj{Age = ,Name = "Hol"},
new TObj{Age = ,Name = "Luk"},
new TObj{Age = ,Name = "Jim"},
new TObj{Age = ,Name = "Tom"},
};
}

Models

测试代码:

static void Main()
{
object result; var x = new Model1();
var y = new Model2();
var z = new Model3(); result = Expression.Eval("20 - 15");
Console.WriteLine(result); result = Expression.Eval("20 > 15");
Console.WriteLine(result); result = Expression.Eval("x.X / x.Y", new SortedDictionary<string, object> { { "x", x } });
Console.WriteLine(result); result = Expression.Eval("x.X + x.Cal()", new SortedDictionary<string, object> { { "x", x } });
Console.WriteLine(result); result = Expression.Eval("x.X + y.Z", new SortedDictionary<string, object> { { "x", x }, { "y", y } });
Console.WriteLine(result); result = Expression.Eval("x.X > x.Y && 20 > 15", new SortedDictionary<string, object> { { "x", x } });
Console.WriteLine(result); result = Expression.Eval("x.X > x.Y || y.B", new SortedDictionary<string, object> { { "x", x }, { "y", y } });
Console.WriteLine(result); result = Expression.Eval("x.X != y.Z", new SortedDictionary<string, object> { { "x", x }, { "y", y } });
Console.WriteLine(result); result = Expression.Eval("y.B ? (x.X - x.Y) : (x.X + x.Y)", new SortedDictionary<string, object> { { "x", x }, { "y", y } });
Console.WriteLine(result); result = Expression.Eval("y.List[4]", new SortedDictionary<string, object> { { "y", y } });
Console.WriteLine(result); result = Expression.Eval("y.List.Count", new SortedDictionary<string, object> { { "y", y } });
Console.WriteLine(result); result = Expression.Eval("{ y.List.Add(120); return y.List.Last(); }", new SortedDictionary<string, object> { { "y", y } });
Console.WriteLine(result); result = Expression.Eval("string.Join(\"\t\", y.List.OrderBy(i => i).Select(i => i.ToString()))", new SortedDictionary<string, object> { { "y", y } });
Console.WriteLine(result); result = Expression.Eval("z.List.Max(x=>x.Age)", new SortedDictionary<string, object> { { "z", z } });
Console.WriteLine(result); result = Expression.Eval("string.Join(\", \",z.List.Select(x=>x.Name));", new SortedDictionary<string, object> { { "z", z } });
Console.WriteLine(result);
}

Program

测试结果:

后来联系到设计模式的工厂模式,试想在项目中包含接口文件,而项目的实现类不包含在项目中,在某个指定的文件中,这样就可以随时修改实现类的文件而不需要重新编译整个项目,于是在Expression类中增加方法:

        /// <summary>
/// 从文件中加载指定接口的实现类的实例
/// </summary>
/// <typeparam name="T">指定的接口的类型</typeparam>
/// <param name="fileName">类型加载的源文件</param>
/// <param name="assemblyPaths">加载类型依赖的程序集路径</param>
/// <returns>实例</returns>
public static T GetInterfaceInstence<T>(string fileName, List<string> assemblyPaths = null)
{
var baseType = typeof(T);
if (!baseType.IsInterface || string.IsNullOrWhiteSpace(fileName) || !File.Exists(fileName))
{
return default(T);
}
var strCode = string.Empty;
using (var file = new StreamReader(fileName, Encoding.Unicode))
{
strCode = file.ReadToEnd();
}
CompilerResults result = Compile(strCode, assemblyPaths); Assembly assembly = result.CompiledAssembly;
var ts = assembly.GetTypes().ToList();
Type aType = ts.FirstOrDefault(x => x.GetInterface(baseType.FullName) != null);
if (aType == null || !aType.IsClass)
{
return default(T);
} return (T)Activator.CreateInstance(aType);
}

关于表达式的编译,后来在网上找到一个解决方案,ExpressionEvaluator.dll

C#动态编译代码,执行一个代码片段,或者从指定文件中加载某个接口的实现类的更多相关文章

  1. 页面上动态编译及执行java代码

    本文地址:http://www.cnblogs.com/liaoyu/p/real-time-compile-and-run-java-code-web-app.html 最近看到同事在页面上编译和执 ...

  2. iOS Interface Builder:在.xib文件中加载另一个.xib文件

    在开发中,经常会用到一个需要重复使用的模块,比如好友列表中每个用户的展示或每条动态,这些都是相同的模版,这样我们就可以把这个部分提取出来放到一个单独的.xib中.那么提取出的.xib如何在其他.xib ...

  3. day02编程语言,Python语言介绍,Python解释器安装,环境变量,Python代码执行,pip,应用程序使用文件的三步骤,变量,变量的三大组成,比较,pycharm

    复习 重点: 1.进制转换:二进制 与十六进制 2.内存分布:栈区 与堆区 # 二进制1111转换十六进制 => 8 4 2 1 => f 10101100111011 => 2a7 ...

  4. 风炫安全web安全学习第三十二节课 Python代码执行以及代码防御措施

    风炫安全web安全学习第三十二节课 Python代码执行以及代码防御措施 Python 语言可能发生的命令执行漏洞 内置危险函数 eval和exec函数 eval eval是一个python内置函数, ...

  5. python with as 以上这段代码执行完毕后,就算在处理过程中出问题了,文件 f 总是会关闭。

    with open("myfile.txt") as f: for line in f: print(line, end="") 以上这段代码执行完毕后,就算在 ...

  6. 动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数

    动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数, 在很多场景下,我们需要在动态加载JS文件的时候,根据加载的状态来进行后续的操作,需要在JS加载成功后,执行另一方法,这个方法是依托在加 ...

  7. Ant执行一个含有main方法的class文件

    目前需要使用ant来执行一个含有main方法的class文件,并且需要通过命令来行传两个参数(start和end)到main方法. <target name="gsp" de ...

  8. extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,你要放行!”

    extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,你要放行!”

  9. 【原】从一个bug浅谈YUI3组件的资源加载

    篇前声明:为了不涉及业务细节,篇内信息统一以某游戏,某功能代替 前不久,某游戏准备内测客户端,开发人员测试过程中发现某功能突然不灵了,之前的测试一切ok,没有发现任何异常,第一反应是,游戏内浏览器都是 ...

随机推荐

  1. Lae程序员小漫画(二),仅供一乐

    Lae软件开发,快乐程序员!

  2. Web程序员常见的5个错误及解决方案

    我是那种脾气暴躁的web用户,但我认为正是如此才驱使我成为一名良好的web开发人员.我会对那些会导致使用网站变得困难的事情恼火,我认为事情越简单越方便越好.这里有五个常见的可用性错误,以及如何避免它们 ...

  3. 一个人的 ClojureScript 技术栈

    作者:题叶链接:https://zhuanlan.zhihu.com/p/24425284来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.今天(昨天)分享完关于 Cloj ...

  4. Spring可以将简单的组件配置

    这次听了老师的课程,觉得还是需要更加集中的去把各种题进行一个分类吧,然后有针对的去准备,虽然据说这一块在面试中也不容易考到,但是毕竟是难点,还是需要好好准备一下的.因为在dp这个方面,我算是一个比较新 ...

  5. web前端的学习.

    web前端的了解 1.前端技术包括JavaScript.ActionScript.CSS.xHTML等“传统”技术与Adobe AIR.Google Gears,以及概念性较强的交互式设计,艺术性较强 ...

  6. 查看 并发请求数及其TCP连接状态【转】

    服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc ...

  7. Clojure web初探

    项目环境:3.2.0-52-generic #78-Ubuntu SMP Fri Jul 26 16:21:44 UTC 2013 x86_64 x86_64 x86_64 GNU/LinuxLein ...

  8. mysql 操作用户权限

    使用可以对mysql数据库用户表有操作权限的用户名登陆mysqlinsert into user(Host,User,Password) values('%','name','password');如 ...

  9. install vim

    常用命令: [0]安装vim: oee@copener:~$ sudo apt-get install vim vim-scripts vim-doc 刚安装完$HOME目录下只有两个文件:.vim/ ...

  10. 浏览器与web客户端的HTTP交互过程

    未经许可谢绝以任何形式对本文内容进行转载! HTTP协议是常见的几种应用层协议之一,当我们用浏览器和web客户端进行交互时html页面等内容的传输都是依靠该协议完成的.值得注意的是,HTTP使用的是T ...