以此代码为例,创建一个调用名为AddNumbers
的方法的自定义委托:
public static int AddNumbers(int a, int b)
{
return a + b;
}
static void Main(string[] args)
{
ParameterExpression
arga = Expression.Parameter(typeof(int)),
argb = Expression.Parameter(typeof(int));
MethodCallExpression result = Expression.Call(typeof(Program_ModelBinding).GetMethod("AddNumbers"), arga, argb);
var deli = Expression.Lambda(result, arga, argb).Compile() as Func<int, int, int>;
Console.WriteLine(deli(2, 4));
}
编译为:
.Lambda #Lambda1<System.Func`3[System.Int32,System.Int32,System.Int32]>(
System.Int32 $var1,
System.Int32 $var2) {
.Call ModelBinding.Program_ModelBinding.AddNumbers(
$var1,
$var2)
}
但是,为了减少干扰并保持堆栈整洁,我希望能够内联AddNumbers
方法,以便它的方法体在代码本身内编译,就好像我这样做:
BinaryExpression result = Expression.Add(arga, argb);
那将编译为:
.Lambda #Lambda1<System.Func`3[System.Int32,System.Int32,System.Int32]>(
System.Int32 $var1,
System.Int32 $var2) {
$var1 + $var2
}
我还要注意,即使方法是非静态的,我宁愿不必处理对象实例。我只想提取方法体,然后在我的代码中内联使用它。
我不知怎的认为System.Reflection.Emit
命名空间有我想要的答案,但我不知道要继续哪个方向。
答案 0 :(得分:1)
没有简单的方法可以做到这一点。
C#编译器将您的方法编译为IL并将其转换回表达式是可能的,但是复杂且成功的程度可以变化。您可以使用现有反编译器的代码来帮助(例如ILSpy是开源的),甚至可能有一个库来执行此操作(我发现的唯一内容是this old library)。
但我的猜测是,所有这些都不值得为了“减少干扰并保持堆栈整洁”。
答案 1 :(得分:0)
一种简单的方法是以编程方式反汇编AddNumbers函数,然后使用该输出驱动Reflection.Emit以动态创建内联代码。
但是,您可能希望某种方法在Main(或接收内联代码的任何方法)中拥有占位符来保存发出的代码。换句话说,您可能不希望发出所有Main,您希望编译器创建除AddNumbers的内联代码之外的所有内容。 (但是你可以对整个Main方法应用相同的反编译/重新编译方法)。
但问题是,需要保留多少空间?如果您内联的代码与AddNumbers一样简单,那就不是问题了。您可以使用内联代码替换原始方法调用,因为它会更短。但是如果内联代码甚至比AddNumbers更复杂,那么内联代码需要更多的空间,并且需要一种方法来让编译器留下足够的空间。
但是随着内联代码变得越来越长,内联的节省变得越来越小,所以也许你可能只对代码的大小有一个硬性限制 - 任何内联代码都必须小于限制。
我想提供一个更好的答案,你需要提供更多关于这个问题的信息:
您是否希望将编译器生成的代码和内联代码混合在一个方法中?或者是一个单独的,动态创建的方法吗?
如果是前者会有一个站点来保存内联代码吗?或者会有不止一个,但固定的,少量的网站?
您预计代码内联的复杂程度(在IL指令数量上)会是多少?
动态生成和编译的C#代码是一个选项吗?根据你对其他问题的回答,Reflection.Emit可能不是一个好的选择 - 相反,你可能需要编译器的智能。