我一直在玩IL,我注意到像Prefix1这样的OpCodes ,文档基本上告诉我不要担心它.当然,这让我很好奇这些各种前缀操作码实际上做了什么.一个快速的谷歌搜索没有发现任何东西,所以我想我会问这里的专家.有谁知道这些意味着什么?
我正在尝试学习一些关于动态生成事件处理程序的知识,并且我很难尝试重新创建这种简单的情况:
public delegate void SomethingHappenedEventHandler(object sender, object args);
public event SomethingHappenedEventHandler SomethingHappened;
// This is the event handler that I want to create dynamically
public void DoSomething(object a, object b)
{
DoSomethingElse(a, b);
}
public void DoSomethingElse(object a, object b)
{
Console.WriteLine("Yay! " + a + " " + b);
}
Run Code Online (Sandbox Code Playgroud)
我用反射器为DoSomething方法生成IL,它给了我:
.method public hidebysig instance void DoSomething(object a, object b) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.1
L_0002: ldarg.2
L_0003: call instance void MyNamespace::DoSomethingElse(object, object)
L_0008: ret …Run Code Online (Sandbox Code Playgroud) 我正在努力学习CIL,即通用中间语言.也称为IL,MSIL等.
(请不要评论问我为什么要这样做或者我将从中获得什么)
我的问题是我在互联网上找到的资源非常少,而且大多数只是简短的博客文章.有帮助吗?
是 il.EmitCall(OpCodes.Callvirt, getter, null);
同样如下:
至 il.Emit(OpCodes.Callvirt,getter);
我不确定如何检查动态生成的IL,所以......这是第二个相关问题.
我有一个对多线程应用程序不安全的对象(在几个方面),我想提供一个内部检查,以确保不会同时访问关键方法.
题
我应该使用哪些技术来检测和阻止多个线程访问我的类?
是否足以在消费者可能使用的所有方法,属性等上跟踪Thread.ID?
考虑这更多是一个学术问题,而不是实际问题.
在重新创建一个轮子,即编写一个迷你ORM /类型映射器时,我发出了一些IL来将对象的属性转换为添加到SqlCommand的SqlParameters.
我的第一次尝试基本上是编写C#代码并将其转换为IL 1:1,从而产生以下代码(完美无缺地工作).请注意,注释表示运行以下发出的IL后的堆栈:
int paramLocIndex = localIndex++;
// Get the type handler [typeHandler]
il.Emit(OpCodes.Call, ClrTypeHandlers[prop.PropertyType].GetType().GetMethod("GetTypeHandler", BindingFlags.NonPublic | BindingFlags.Static));
// Load the object [typeHandler, object]
il.Emit(OpCodes.Ldloc_0);
// Get the property value [typeHandler, value]
il.Emit(OpCodes.Call, prop.GetMethod);
// Box the value [typeHandler, boxedValue]
il.Emit(OpCodes.Box, prop.PropertyType);
// Let the type handler create the param [param]
il.Emit(OpCodes.Callvirt, typeof(SqlTypeHandler).GetMethod("CreateParamFromValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object) }, null));
// Store the parameter as a variable []
il.DeclareLocal(typeof(SqlParameter));
il.Emit(OpCodes.Stloc, paramLocIndex);
// Load the parameter again …Run Code Online (Sandbox Code Playgroud) 我正在读第二本书但它仍然不明显.
我的问题是:编译IL语言的次数:a)每次从开始运行应用程序的执行.b)一次,在第一次执行后.
以下C#代码:
short first = 1;
short second = 2;
bool eq1 = (first.Equals(second));
Run Code Online (Sandbox Code Playgroud)
该代码转换为:
IL_0001: ldc.i4.1
IL_0002: stloc.0 // first
IL_0003: ldc.i4.2
IL_0004: stloc.1 // second
IL_0005: ldloca.s 00 // first
IL_0007: ldloc.1 // second
IL_0008: call System.Int16.Equals
IL_000D: stloc.2 // eq1
Run Code Online (Sandbox Code Playgroud)
ldloca.s 00 - 使用索引indx,short form加载局部变量的地址.
ldloc.1 - 将局部变量1加载到堆栈上.
为什么两个命令都不是ldloca.s(两个变量都是short类型)?
根据MSDN,如果定义了结构,该结构应该覆盖从对象类继承的所有方法.建议在调用任何继承的方法(如ToString)时避免不必要的装箱.
根据MSDN,为了确定是否以及何时发生装箱,可以在MSIL代码中找到IL指令"框".
我写了下面的测试来看拳击.
using System;
namespace TestingBoxing
{
public struct StructX
{
public int member1;
public int member2;
}
public class Program
{
public static void Main(string[] args)
{
StructX s1;
s1.member1 = 2;
s1.member2 = 5;
string str = s1.ToString();
Console.WriteLine(str);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,尽管在结构定义中未调用ToString,但在下面的MSIL代码中无法看到装箱指令.
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] valuetype TestingBoxing.StructX s1,
[1] string str)
IL_0000: ldloca.s s1
IL_0002: ldc.i4.2
IL_0003: stfld …Run Code Online (Sandbox Code Playgroud) 在已编译的C#程序上使用ILDASM.exe时,它会显示方法中的每条指令都有一个标签.
例如:
IL_0001: ldc.i4.4
IL_0002: stloc.0
IL_0003: ldc.r8 12.34
IL_000c: stloc.1
IL_000d: ldc.r8 3.1415926535897931
IL_0016: stloc.2
IL_0017: ldstr "Ehsan"
IL_001c: stloc.3
IL_001d: ret
Run Code Online (Sandbox Code Playgroud)
为什么是这样?这样做效率不高或者CIL编译器本身是否优化这些标签?