我有一些代码可以使用Func<>
和System.Linq.Expressions
等生成各种Expression.Lambda<Func<>>.Compile()
代理。我希望能够将生成的函数序列化到程序集中供以后使用。在过去,我已经使用System.Reflection.Emit做了一些事情,但是现在Linq表达式我宁愿不再去那条路了。
是否有机制将编译表达式或某种桥接从Expressions
命名空间序列化到Emit
命名空间?
修改
背景的一些背景: 我正在研究一个查询引擎(主要是为了我自己的启发和享受)。给定一个SQL语句,我想解析并将其转换为lambda函数,然后将其序列化为磁盘以供以后使用(并重复执行)。
在伪代码中,我就是这样:
Func<IEnumerable<T>, IEnumerable<T1>> query = Query.Parse<T, T1>("Select field AS A, field1 AS B from T where T.field2 > 5");
(其中字段, field1 和 field2 是 Type T 和 A的属性和 B 是 Type T1 的属性。
我可以将<T>
的任何枚举传递给query
,然后返回一个符合查询条件的<T1>
枚举。
所以我想将query
序列化为磁盘作为已编译的程序集,以便日后我可以加载它并评估<T>
的不同集合而无需解析和编译它。我正在想象一下:
AssemblyBuilder builder = new AssemblyBuilder(...);
ModuleBuilder module = builder.DefineDynamicModule(...);
TypeBuilder type = module.DefineType(...);
type.AddMethod(query); // <--- where this piece does not exist as far as I know
builder.Emit(...)
答案 0 :(得分:3)
我不确定你的大图是什么,但纯粹看你的第二段,你可以编写基于表达式的纯代码,构建它,然后使用“Reflection.Emit”语言添加 - 在Reflector中打开你的程序集 - 在。这段元元素技巧将向您展示动态生成Expression / Lambda代码所需的Reflection.Emit语句。
-Oisin
答案 1 :(得分:3)
我认为没有办法做到这一点。毕竟,Expression
可以捕获任意运行时值,这些值无法序列化为程序集。
看起来您可以通过调用expr.Compile().Method.GetMethodBody().GetILAsByteArray()
来获取IL作为字节,然后可以将其写入程序集中的MethodBuilder
,然后您可以将其写入文件。不幸的是,这不起作用 - GetMethodBody()
调用失败,因为委托是动态的。
答案 2 :(得分:3)
LambdaExpression有一个CompileToMethod方法,该方法以MethodBuilder为目标。使用this和Reflection.Emit,您应该能够创建一个类并将其写入程序集。