使用Reflection.Emit创建对象数组出现问题

3
我正在尝试发出一个我认为很简单的对象数组,结果应该类似于以下示例代码。
object[] parameters = new object[] { a, b, };

当我使用VS用C#编写上述代码时,我会得到以下 IL。正如预期的那样,这将起作用。
.locals init (
[0] object[] parameters,
[1] object[] CS$0$0000)

然而,当我尝试直接发出IL时,我只得到了一个索引为1的初始化数组。有人能帮忙告诉我在哪里出错了吗?

这是我使用的Emit代码:

int arraySize = 2;
LocalBuilder paramValues = ilGenerator.DeclareLocal(typeof(object[]));
paramValues.SetLocalSymInfo("parameters");
ilGenerator.Emit(OpCodes.Ldc_I4_S, arraySize);
ilGenerator.Emit(OpCodes.Newarr, typeof(object));
ilGenerator.Emit(OpCodes.Stloc, paramValues);

以下是生成的IL代码:

.locals init (
[0] object[] objArray)

其余的IL代码在这两个解决方案中是相同的,但由于某种原因,.locals init 部分不同。
3个回答

3

C#编译器生成的代码类似于这样:

object[] temp = new object[2];
temp[0] = (object)a;
temp[1] = (object)b;
parameters = temp;

临时变量是您所看到的CS$0$0000。我认为它这样做是为了确保在初始化数组时可能引发的异常不会在“参数”中留下部分初始化的数组,从而导致代码捕获异常时出现意外的失败。按照编写的方式,命名的变量要么为空,要么完全初始化。好主意。


这很有道理,让我想到了如何重构我的例程。感谢您的提示。 - JoeGeeky

0
如果您只声明一个本地变量(paramValues),那么只会声明一个本地变量。如果需要第二个本地变量,请再次调用DeclareLocal。但我不明白为什么您需要这样做?声明您不需要的本地变量是没有意义的。

谢谢,显然我误解了这个意思。目前这是 VS 生成的代码和 EMIT 生成的代码之间唯一的区别。我必须重新开始考虑。 - JoeGeeky

0

CS$0$0000变量在这里是因为编译器没有优化变量的创建和使用。它会自动创建一个变量用于代码中的new object[] { a, b, }部分,然后将创建的对象赋值给object[] parameters变量。 这种行为主要是由于IL的基于堆栈的特性。 尝试在发布模式下运行代码,看看是否进行了优化。


那么,为什么这是个问题呢?两个生成的IL在效果上是相等的。 - Kenan E. K.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接