问题标签 [il]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
3802 浏览

c# - 动态生成的 IL 中的值类型转换

更新
一年多后,我终于意识到了这种行为的原因。本质上,一个对象不能被拆箱到不同于它被装箱的类型(即使该类型转换或转换为目标类型),如果你不知道正确的类型,你必须以某种方式发现它。分配可能是完全有效的,但自动发生这种情况是不可行的。

例如,即使一个字节适合 Int64,您也不能将一个字节拆箱为 long。您必须将一个字节拆箱为一个字节,然后对其进行强制转换。

如果您没有足够的信息来执行此操作,则必须使用另一种方法(如下所示)。

表示和身份

原始问题

我正在与 IL 合作以提高许多通常通过反射处理的任务的性能。为了做到这一点,我大量使用了这个DynamicMethod类。

我已经编写了用于设置对象属性的动态方法。这允许开发人员仅根据名称动态设置属性。这对于将数据库中的记录加载到业务对象等任务非常有用。

但是,我被困在一件(可能很简单)的事情上:将值类型,甚至更大的类型转换为更小的类型(例如将一个字节的值放入 Int32 中)。

这是我用来创建动态属性设置器的方法。请注意,我已经删除了除 IL 生成部分之外的所有内容。

我尝试在 IL 生成时检查属性类型并使用 conversion OpCodes。尽管如此,代码仍然会抛出一个InvalidCastException. 这个例子显示了一个检查(我认为)应该确保堆栈上的任何值都被转换为匹配它被分配到的属性的类型。

我还尝试在取消装箱值类型之前或之后进行强制转换,例如:

我想我可以创建 IL 来动态创建Convert对象并调用ChangeType(),但是当大多数时候这甚至不是问题(当类型匹配时,没有问题)时,这似乎很浪费。

总结问题:当我将值类型传递给动态生成的方法时,如果它与分配给它的属性类型不完全匹配,则会抛出 InvalidCastException,即使目标类型的大小更大比源类型。我尝试过的类型转换不起作用。

如果您需要更多信息来回答问题,请告诉我。

编辑:@JeffN825 在关注转换方面走在了正确的轨道上。我曾考虑过 System.Convert 类,但由于过于昂贵而将其排除在外。但是,有了目标类型,您可以创建一个只调用适合该类型的方法的例程。这(基于测试)似乎相对便宜。生成的代码如下所示:

当然,这会导致一个巨大的 if/else 语句(当所有类型都实现时),但它与 BCL 所做的没有什么不同,并且此检查仅在生成 IL 时执行,而不是在每次调用时执行。因此,它选择正确的 Convert 方法并编译一个 Call 到它。

请注意,这OpCodes.Call是必需的,而不是OpCodes.Callvirt,因为Convert对象的方法是静态的。

表现可观;随机测试显示对动态生成的 set 方法的 1,000,000 次调用大约需要 40 毫秒。打败了反射。

0 投票
1 回答
330 浏览

c# - 从 ILAsm 文件中删除 .property 语句以供生产使用是否可以?

仍在基于修改 ILAsm 文件开发我的混淆程序。(参考。不应混淆哪些 C# 方法名称?

在查看 ILAsm 代码时,我得到的印象是 .property 语句不用于任何事情,至少不用于程序执行。我是否认为他们只是为 Visual Studio 提供元数据?如果是这样,当 ILAsm 代码仅用于生成永远不会与 Visual Studio 一起使用的生产模块时,是否可以简单地删除它们?

0 投票
1 回答
312 浏览

.net - 如何捕捉一个int

我正在使用 IL 抛出一个 Int32 并抓住它。这只是出于好奇,我不想实现任何目标,所以请不要告诉我抛出异常而不是 int。

这不起作用,我得到字符串“In Object catch”,但是当我尝试拆箱时,我得到一个 System.InvalidCastException: Specified cast is not valid。我怎样才能得到抛出的东西的价值?

0 投票
2 回答
2950 浏览

c# - IL: ldfld 与 ldflda

我正在使用 Mono.Cecil 编写一个小型 IL 编织应用程序,这需要我在 IL 级别上操作目标程序集。

我的问题很简单,但我仍然觉得这件事很混乱。指令之间的实际区别是什么?ldfldldflda

我咨询过msdn,似乎在ldfld获取字段的值时,ldflda获取了字段的地址。好吧……但这意味着什么?我一开始以为前者用于值类型(和字符串),后者用于引用类型,但我编译了一个 C# 片段并在 Reflector 中检查它,结果证明我错了。

ldflda当 C# 编译器发出而不是 时,我无法找到任何不同的模式ldfld,并且我的搜索没有发现任何可以解释这一点的文章。那么什么时候用ldflda代替ldfld呢?

任何帮助将不胜感激。

0 投票
2 回答
546 浏览

c# - 如何在 C# 中生成新类型

我真的很想在运行时生成一个新类型。本质上,我想创建看起来像这样的类型:

某些类型会根据用户/数据库输入而有所不同,因此除了在运行时创建类型之外,我无法真正完成它。还有更多的复杂性,但我想让我的问题简单,所以我在这里只问基本问题。我需要做更多的一代,就像你在这里看到的那样。

我认为使用它会很酷Reflection.Emit,但后来我意识到生成代码并在内存中编译可能更容易。有谁知道哪个更好?我真的很想看到一个如何做其中任何一个的例子。

0 投票
1 回答
140 浏览

.net - .maxstack 1 分配的 1 个堆栈的大小

当我说.maxstack 1,它是如何工作的?我可以将任何数据类型推入堆栈吗?它如何决定堆栈的大小。它是过早完成的,还是在运行时完成的?

Edit1:即使我只在堆栈上推送一个参数,它如何决定它的内存分配?它的数据类型是在编译时还是运行时识别的?

0 投票
1 回答
1205 浏览

c# - 将值添加到字典的 C# IL 代码

我有一个动态方法,它采用 aDataRecord并将数据映射到某种类型的对象。

来自DynamicMethod_ILGenerator

这些对象有一个类型的字典Dictionary<string,object>来保存 DataRecord 中无法绑定的任何属性。

但是我似乎无法弄清楚如何将这些添加到字典中。

我知道我必须Emit(OpCodes.Callvirt, addMethod)查字典,但无论我尝试什么,我都无法弄清楚如何让它发挥作用。

0 投票
1 回答
2011 浏览

c# - 使用 Mono.Cecil 从 ByReferenceType 获取泛型参数

我有一个获取参数的方法,例如:

使用 Cecil 枚举参数会产生一个 ByReferenceType。调用 GetElementType() 以尝试取消对参数的引用会返回带有全名的 TypeReference:

不知何故,它失去了泛型参数,不再是 GenericInstanceType。

如何正确取消引用 byref 参数,并获得实际的泛型实例类型?

0 投票
3 回答
2403 浏览

c# - C# 为 ++ 运算符生成 IL - 何时以及为何前缀/后缀表示法更快

由于这个问题是关于增量运算符和前缀/后缀符号的速度差异,我将非常仔细地描述这个问题,以免 Eric Lippert 发现它并激怒我!

(有关我为什么要询问的更多信息和详细信息,请访问 http://www.codeproject.com/KB/cs/FastLessCSharpIteration.aspx?msg=3899456#xx3899456xx/

我有四个代码片段如下: -

(1) 分开,前缀:

(2) 分开,后缀:

(3) 索引器,后缀:

(4) 索引器,前缀:

我试图做的是证明/反驳在这种情况下前缀和后缀表示法之间是否存在性能差异(即一个局部变量,因此不是易失性的,不能从另一个线程更改等),如果有,为什么会这样.

速度测试表明:

  • (1) 和 (2) 以相同的速度运行。

  • (3) 和 (4) 以相同的速度运行。

  • (3)/(4) 比 (1)/(2) 慢约 27%。

因此,我得出的结论是,选择前缀表示法而不是后缀表示法本身并没有性能优势。但是,当实际使用操作的结果时,这会导致代码比简单地丢弃更慢。

然后我查看了使用 Reflector 生成的 IL 并发现以下内容:

  • IL 字节数在所有情况下都是相同的。

  • .maxstack 在 4 到 6 之间变化,但我认为这仅用于验证目的,因此与性能无关。

  • (1) 和 (2) 生成完全相同的 IL,因此时序相同也就不足为奇了。所以我们可以忽略(1)。

  • (3) 和 (4) 生成了非常相似的代码 - 唯一相关的区别是 dup 操作码的定位以说明操作的结果。同样,时间相同也就不足为奇了。

因此,我比较了 (2) 和 (3) 以找出可能导致速度差异的原因:

  • (2) 两次使用 ldloc.0 操作(一次作为索引器的一部分,然后作为增量的一部分)。

  • (3) 使用 ldloc.0 紧跟一个 dup op。

因此,对于 (1) (和 (2)) 递增 j 的相关 IL 是:

(3) 看起来像这样:

(4) 看起来像这样:

现在(终于!)这个问题:

(2) 是否更快,因为 JIT 编译器识别出一种模式,ldloc.0/ldc.i4.1/add/stloc.0即简单地将局部变量增加 1 并对其进行优化?(并且dup(3)和(4)中的存在打破了这种模式,因此错过了优化)

还有一个补充:如果这是真的,那么至少对于(3),不会dup用另一个ldloc.0重新引入该模式来替换 吗?

0 投票
4 回答
2581 浏览

c# - 为 .Net 平台生成 IL

我正在用 C# 编写一个小型编译器,并计划使用 .Net 平台生成 IL 指令System.Reflection.Emit。我的问题是,建议使用System.Reflection.Emit为生产编译器生成 IL。

如果不建议使用System.Reflection.Emit为生产编译器生成 IL,我们是否有用于此目的的替代库/工具?