我有一些代码使用 System.Linq.Expressions
和 Expression.Lambda.Compile 生成各种 Func<>
委托()
等。我希望能够将生成的函数序列化为程序集以供以后使用。过去我用 System.Reflection.Emit 做了一些事情,但现在使用 Linq Expressions 我不想再走这条路了。
是否有一种机制可以序列化已编译的表达式或从 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");
其中 field、field1 和 field2 是 T 类型 的属性, A 和 B 是 T1 类型的属性。
我可以将
的任何枚举传递给 query
并返回与查询条件匹配的
枚举。
因此,我想将 query
作为已编译的程序集序列化到磁盘,以便稍后我可以加载它并评估不同的
集,而无需解析和编译它。我正在想象一些类似的事情:
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(...)
I've got some code that generates various Func<>
delegates using System.Linq.Expressions
and Expression.Lambda<Func<>>.Compile()
etc. I would like to be able to serialize the generated functions into an assembly for later use. In the past I've done some stuff with System.Reflection.Emit but now that Linq Expressions I'd rather not go that route again.
Is there a mechanism to serialize a compiled expression or some sort of bridge from the Expressions
namespace to the Emit
namespace?
Edit
Some background for context:
I am working on a query engine (mostly for my own edification and enjoyment). Given a SQL statement I would like to parse and transform it into a lambda function and then serialize it to disk for later (and repeated execution).
In pseudo code I am to this point:
Func<IEnumerable<T>, IEnumerable<T1>> query = Query.Parse<T, T1>("Select field AS A, field1 AS B from T where T.field2 > 5");
(where field, field1 and field2 are properties of Type T and A and B are properties of Type T1.
and I can pass any enumeration of <T>
to query
and get back and an enumeration of <T1>
which matches the query criteria.
So I would like to serialize query
to disk as an already compiled assembly so at a later date I can load it and evaluate different sets of <T>
without parsing and compiling it. I am picturing something along the lines of:
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(...)
发布评论
评论(3)
LambdaExpression 有一个面向 MethodBuilder 的 CompileToMethod 方法。使用它和 Reflection.Emit 您应该能够创建一个类并将其写入程序集。
LambdaExpression has a CompileToMethod method that targets a MethodBuilder. Using this and Reflection.Emit you should be able to create a class and write it to an assembly.
我不确定您的大局到底是什么,但纯粹看看您的第二段,您可以编写纯基于表达式的代码,构建它,然后使用“Reflection.Emit”语言插件在 Reflector 中打开程序集。这段元元技巧将向您展示动态生成表达式/Lambda 代码所需的 Reflection.Emit 语句。
-奥辛
I'm not sure what exactly your bigger picture is but looking purely at your second paragraph, you can write pure Expression based code, build it, and then open your assembly in Reflector using the "Reflection.Emit" language add-in. This piece of meta-meta trickery will show you the Reflection.Emit statements needed to generate your Expression/Lambda code dynamically.
-Oisin
我不认为有任何办法可以做到这一点。毕竟,
Expression
可以捕获任意运行时值,而这些值无法序列化到程序集中。看来您可以通过调用 expr.Compile().Method.GetMethodBody().GetILAsByteArray() 来解决这个问题,以字节形式获取 IL,然后将其写入
MethodBuilder
位于程序集中,然后您可以将其写入文件。不幸的是,这不起作用 -GetMethodBody()
调用失败,因为委托是动态的。I don't think that there's any way to do this. After all, an
Expression
can capture arbitrary run time values, which couldn't be serialized into an assembly.It would seem like you could get around this by calling
expr.Compile().Method.GetMethodBody().GetILAsByteArray()
to get the IL as bytes, which could then be written to aMethodBuilder
in an assembly which you could then write to file. Unfortunately, this won't work - theGetMethodBody()
call fails because the delegate is dynamic.