无法在 C# 中使用转换为 IL 的表达式调用静态方法
Cannot call static methods using expression converted to IL in C#
这是我第一次尝试从表达式生成 IL,但我无法让它工作。我无法使用 IL 生成器调用静态方法。
我的Class结构是
public class TestClass
{
public static A Process(IServiceFactory factory, A a)
{
a.Value = 40;
return a;
}
}
public class A
{
public int Value { get; set; }
}
我需要生成执行此操作的 IL
a.Value = 10;
TestClass.Process(factory,a)
我设法生成的 IL 代码是
IL_0000: ldarg.1
IL_0001: castclass A
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldc.i4.0
IL_000a: ldelem.ref
IL_000b: castclass System.Func`1[System.Int32]
IL_0010: callvirt Int32 Invoke()/System.Func`1[System.Int32]
IL_0015: callvirt Void set_Value(Int32)/A
IL_001a: ldloc.0
IL_001b: ldarg.0
IL_001c: ldc.i4.1
IL_001d: ldelem.ref
IL_001e: castclass IServiceFactory
IL_0023: ldarg.1
IL_0024: castclass A
IL_0029: call A Process(IServiceFactory, A)/TestClass
IL_002e: ret
注意:它从数组中加载实际的工厂对象。
此 IL 生成 InvalidProgramException。但是,如果我可以将静态方法转换为实例方法并在 TestClass 实例中执行调用,它就可以正常工作。
不知道哪里错了
您似乎在堆栈中加载了太多内容。第一部分似乎不错(忽略它与您想要的效果不符):
IL_0000: ldarg.1
IL_0001: castclass A
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldc.i4.0
IL_000a: ldelem.ref
IL_000b: castclass System.Func`1[System.Int32]
IL_0010: callvirt Int32 Invoke()/System.Func`1[System.Int32]
IL_0015: callvirt Void set_Value(Int32)/A
大致相当于以下 C#:
A a = (A) arg1;
a.Value = ((Func<int>)arg0[0]).Invoke();
我不知道生成的方法参数是什么,因为您没有 post 它们。不管怎样,继续前进:
IL_001a: ldloc.0 // {a}
IL_001b: ldarg.0 // {a, arg0}
IL_001c: ldc.i4.1 // {a, arg0, 1}
IL_001d: ldelem.ref // {a, arg0[1]}
IL_001e: castclass IServiceFactory // {a, (IServiceFactory) arg0[1] }
IL_0023: ldarg.1 // {a, (IServiceFactory) arg0[1], arg1 }
IL_0024: castclass A // {a, (IServiceFactory) arg0[1], (A) arg1 }
IL_0029: call A Process(IServiceFactory, A)/TestClass // {a, TestClass.Process( (IServiceFactory) arg0[1], (A) arg1 ) }
IL_002e: ret
我在每条指令后用堆栈状态对 IL 进行了注释。您可以看到,当您到达 return 指令时,堆栈中有两个值。 IL_001a 处的 ldloc.0
似乎是一个错误,不应该存在(此外,IL_0023-0024 可以用简单的 ldloc.0
代替,而不是重新加载 arg。 1 并将其转换为 A
)。这可以解释为什么当它不是静态方法时它可以工作:堆栈上的附加对象被视为调用方法的对象,因此它被正确使用。
根据您生成的方法是否应该 return 一个值,您可能需要额外的 pop
来清除 TestClass.Process
的 return 值方法出栈。既然你说它作为实例方法工作,这听起来像是生成的方法 returns 一个值,所以你不需要 pop
.
这是我第一次尝试从表达式生成 IL,但我无法让它工作。我无法使用 IL 生成器调用静态方法。
我的Class结构是
public class TestClass
{
public static A Process(IServiceFactory factory, A a)
{
a.Value = 40;
return a;
}
}
public class A
{
public int Value { get; set; }
}
我需要生成执行此操作的 IL
a.Value = 10;
TestClass.Process(factory,a)
我设法生成的 IL 代码是
IL_0000: ldarg.1
IL_0001: castclass A
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldc.i4.0
IL_000a: ldelem.ref
IL_000b: castclass System.Func`1[System.Int32]
IL_0010: callvirt Int32 Invoke()/System.Func`1[System.Int32]
IL_0015: callvirt Void set_Value(Int32)/A
IL_001a: ldloc.0
IL_001b: ldarg.0
IL_001c: ldc.i4.1
IL_001d: ldelem.ref
IL_001e: castclass IServiceFactory
IL_0023: ldarg.1
IL_0024: castclass A
IL_0029: call A Process(IServiceFactory, A)/TestClass
IL_002e: ret
注意:它从数组中加载实际的工厂对象。
此 IL 生成 InvalidProgramException。但是,如果我可以将静态方法转换为实例方法并在 TestClass 实例中执行调用,它就可以正常工作。
不知道哪里错了
您似乎在堆栈中加载了太多内容。第一部分似乎不错(忽略它与您想要的效果不符):
IL_0000: ldarg.1
IL_0001: castclass A
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldc.i4.0
IL_000a: ldelem.ref
IL_000b: castclass System.Func`1[System.Int32]
IL_0010: callvirt Int32 Invoke()/System.Func`1[System.Int32]
IL_0015: callvirt Void set_Value(Int32)/A
大致相当于以下 C#:
A a = (A) arg1;
a.Value = ((Func<int>)arg0[0]).Invoke();
我不知道生成的方法参数是什么,因为您没有 post 它们。不管怎样,继续前进:
IL_001a: ldloc.0 // {a}
IL_001b: ldarg.0 // {a, arg0}
IL_001c: ldc.i4.1 // {a, arg0, 1}
IL_001d: ldelem.ref // {a, arg0[1]}
IL_001e: castclass IServiceFactory // {a, (IServiceFactory) arg0[1] }
IL_0023: ldarg.1 // {a, (IServiceFactory) arg0[1], arg1 }
IL_0024: castclass A // {a, (IServiceFactory) arg0[1], (A) arg1 }
IL_0029: call A Process(IServiceFactory, A)/TestClass // {a, TestClass.Process( (IServiceFactory) arg0[1], (A) arg1 ) }
IL_002e: ret
我在每条指令后用堆栈状态对 IL 进行了注释。您可以看到,当您到达 return 指令时,堆栈中有两个值。 IL_001a 处的 ldloc.0
似乎是一个错误,不应该存在(此外,IL_0023-0024 可以用简单的 ldloc.0
代替,而不是重新加载 arg。 1 并将其转换为 A
)。这可以解释为什么当它不是静态方法时它可以工作:堆栈上的附加对象被视为调用方法的对象,因此它被正确使用。
根据您生成的方法是否应该 return 一个值,您可能需要额外的 pop
来清除 TestClass.Process
的 return 值方法出栈。既然你说它作为实例方法工作,这听起来像是生成的方法 returns 一个值,所以你不需要 pop
.