在其他BlockExpressions中执行额外的BlockExpressions会影响代码生成
本文关键字:BlockExpressions 影响 代码生成 其他 执行 | 更新日期: 2023-09-27 18:30:07
在C#表达式树中,
.Block(
ConsoleApplication2.A $var1,
ConsoleApplication2.B $var2) {
.Block() {
.Block() {
$var1 = .New ConsoleApplication2.A();
$var1
};
.Block() {
$var2 = .New ConsoleApplication2.B($var1);
$var2
}
}
}
与相比,上述表达式是否生成较差的代码质量
.Block(
ConsoleApplication2.A $var1,
ConsoleApplication2.B $var2) {
$var1 = .New ConsoleApplication2.A();
$var2 = .New ConsoleApplication2.B($var1);
}
它们在功能上是等效的,但第一个是我经常通过基于访问者模式的修改得到的。
有没有办法将所有占位符(即没有变量??)的块"减少"或"折叠"到父块中?也许会利用另一位访客?我想不通。
在IL级别,没有块的概念,所以我希望这两个表达式产生相同(或非常相似)的IL代码。
要验证这一点,可以使用Reflection.Emit和CompileToMethod()
创建一个程序集,该程序集在单独的方法中同时具有这两个选项。然后,您可以使用ildasm查看两种方法的IL,以验证代码是否确实相同:
.locals init (
[0] class [ConsoleApplication1]ConsoleApplication1.A a,
[1] class [ConsoleApplication1]ConsoleApplication1.B b)
L_0000: newobj instance void [ConsoleApplication1]ConsoleApplication1.A::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: newobj instance void [ConsoleApplication1]ConsoleApplication1.B::.ctor(class [ConsoleApplication1]ConsoleApplication1.A)
L_000c: stloc.1
L_000d: ret
创建程序集的代码可能如下所示:
var var1 = Expression.Variable(typeof(A), "var1");
var var2 = Expression.Variable(typeof(B), "var2");
Expression<Action> withBlocks =
Expression.Lambda<Action>(
Expression.Block(
new[] { var1, var2 },
Expression.Block(
Expression.Block(
Expression.Assign(
var1,
Expression.New(typeof(A).GetConstructors().Single())),
var1),
Expression.Block(
Expression.Assign(
var2,
Expression.New(
typeof(B).GetConstructors().Single(), var1)),
var2))));
Expression<Action> withoutBlocks =
Expression.Lambda<Action>(
Expression.Block(
new[] { var1, var2 },
Expression.Assign(
var1, Expression.New(typeof(A).GetConstructors().Single())),
Expression.Assign(
var2,
Expression.New(typeof(B).GetConstructors().Single(), var1))));
var assembly = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName("test"), AssemblyBuilderAccess.Save);
var module = assembly.DefineDynamicModule("test.dll");
var type = module.DefineType("Type");
var withBlocksMethod = type.DefineMethod(
"WithBlocks", MethodAttributes.Public | MethodAttributes.Static,
typeof(void), Type.EmptyTypes);
withBlocks.CompileToMethod(withBlocksMethod);
var withoutBlocksMethod = type.DefineMethod(
"WithoutBlocks", MethodAttributes.Public | MethodAttributes.Static,
typeof(void), Type.EmptyTypes);
withoutBlocks.CompileToMethod(withoutBlocksMethod);
type.CreateType();
assembly.Save("test.dll");