我想使用System.Reflection.Emit命名空间为2D数组构造生成IL .
我的C#代码是
Array 2dArr = Array.CreateInstance(typeof(int),100,100);
Run Code Online (Sandbox Code Playgroud)
使用ildasm,我意识到为上面的C#代码生成了以下IL代码.
IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b: ldc.i4.s 100
IL_000d: ldc.i4.s 100
IL_000f: call class [mscorlib]System.Array [mscorlib]System.Array::CreateInstance(class [mscorlib]System.Type,
int32,
int32)
Run Code Online (Sandbox Code Playgroud)
我能够生成最后三个IL语句,如下所示.
MethodInfo createArray = typeof(Array).GetMethod("CreateInstance",
new Type[] { typeof(Type),typeof(int),typeof(int) });
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Call, createArray);
Run Code Online (Sandbox Code Playgroud)
但我不清楚如何生成拳头IL声明(即IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle))
你有什么主意吗?
此外,有人能指出一些关于如何使用System.Reflection.Emit命名空间以生成IL代码的好教程/文档吗?
我希望能够替换参数的对象引用,而不必使用ref关键字.
我避免使用ref的原因是保留了查找Add(T item)方法的集合初始化程序调用,我需要让集合类用它的接口的不同实现替换引用.
我尝试了几种不同的方法来做到这一点.首先,我尝试使用未记录的关键字__makeref,__refvalue并且__reftype.
其次,我尝试DynamicMethod用一些IL 来创建一个IL,它试图模仿我从一个带有ref参数的反汇编类似调用中观察到的东西.
以下是一些演示代码:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection.Emit;
using System.Reflection;
interface IRecord
{
string Name { get;}
}
class ImpA : IRecord
{
public string Name { get { return "Implementation A"; } }
}
class ImpB : IRecord
{
public string Name { get { return "Implementation B"; } }
}
class RecordList<T> : IEnumerable<T>
{
//// Standard Add method (of course …Run Code Online (Sandbox Code Playgroud) gcc有一个-s选项来生成汇编源代码.csc(MS C#编译器)或dmcs(单声道C#编译器)是否具有等价性?我的意思是那些编译器提供了生成可以读取而不是执行二进制文件的IL源代码的选项吗?
首先,我必须为自己是一个 IL 菜鸟而道歉。我在生成 IL 代码来调用具有此签名的方法时遇到困难:
public void CallMethod2(string name, object[] args, object[] genericArgs)
Run Code Online (Sandbox Code Playgroud)
我可以调用一个具有单个数组的方法,如下所示:
public void CallMethod1(string name, object[] args)
Run Code Online (Sandbox Code Playgroud)
使用以下 IL 作品:
ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, invokerMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
但随后我使用以下 IL 尝试使用此 IL 调用 CallMethod2:
ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod2", BindingFlags.Instance | BindingFlags.Public | …Run Code Online (Sandbox Code Playgroud) 我正在教自己CIL并且到目前为止一直做得很好(昨天真的开始)但我遇到了一个我无法弄清楚的问题.我正在提示用户输入一个int(int32),然后将其存储并转换为浮点并显示它.然而,无论我输入什么都是不同的浮动.这是我的代码:
.assembly variables {}
.method public static void main() cil managed
{
.entrypoint
.maxstack 8
.locals init (float64)
ldstr "Enter a digit: "
call void [mscorlib]System.Console::WriteLine(string)
call int32 [mscorlib]System.Console::Read()
conv.r8
stloc.0
ldstr "as a float: "
call void [mscorlib]System.Console::WriteLine(string)
ldloc.0
dup
call void [mscorlib]System.Console::Write(float64)
stloc.0
ldstr "Stored in location 0"
call void [mscorlib]System.Console::WriteLine(string)
ldloc.0
conv.i4
call void [mscorlib]System.Console::WriteLine(int32)
call int32 [mscorlib]System.Console::Read() // to pause before closing window
pop
ret
}
Run Code Online (Sandbox Code Playgroud)
我只是在和CIL搞砸,但我觉得为了清晰起见,我会把整个例子都扔进去.它编译得很好但是当我输入5时它返回53作为浮点数和转换后的int32.
有人可以说明我做错了什么!
编辑:感谢Marc Gravell,我能够弄明白.对于那些感兴趣的人,这里是正确的代码:
.assembly variables {}
.method …Run Code Online (Sandbox Code Playgroud) 因此,我试图弄清楚带有 blob 的自定义属性到底是如何工作的。二进制格式看起来非常...奇怪。
来自 ildasm 的示例
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) =
( 01 00 19 57 69 6E 64 6F 77 73 50 68 6F 6E 65 2C // ...WindowsPhone,
56 65 72 73 69 6F 6E 3D 76 38 2E 30 01 00 54 0E // Version=v8.0..T.
14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 // .FrameworkDispla
79 4E 61 6D 65 11 57 69 6E 64 6F 77 73 20 …Run Code Online (Sandbox Code Playgroud) 当我试图了解 Round 实际上做了什么时,我最终查看了一个简单控制台程序的 IL(从 C# .NET 4.5 编译器发出):
.maxstack 2
.locals init (float64 V_0,
float64 V_1)
IL_0000: ldc.r8 2.0001232314135344
IL_0009: stloc.0
IL_000a: ldloca.s V_0
IL_000c: call instance string [mscorlib]System.Double::ToString()
IL_0011: call void [mscorlib]System.Console::WriteLine(string)
IL_0016: ldloc.0
IL_0017: ldc.i4.5
IL_0018: call float64 [mscorlib]System.Math::Round(float64,
int32)
IL_001d: stloc.1
IL_001e: ldloca.s V_1
IL_0020: call instance string [mscorlib]System.Double::ToString()
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ret
Run Code Online (Sandbox Code Playgroud)
我注意到有关 IL_001d 和 IL_001e 的说明。它们对我来说似乎是多余的,将值存储在本地并在此之后立即加载相同的值。删除它们并重新组装 IL 给我一个 NullReferenceException,所以我猜它有一定的意义。但我想不通。
那么 NullReferenceException 是从哪里来的呢?为什么编译器会发出这两条指令?没有比上面给出的更多的 IL,当然除了一些元。
例如,如果我有
namespace a
namespace b
{
class C...
class D...
}
Run Code Online (Sandbox Code Playgroud)
那么在编译之后,在IL文件中,命名空间信息在哪里?我是否得到两个名为abC和abD的类,其中类名以名称空间名称作为前缀?
或者我在汇编文件中获得了一个名称空间ab,并在其中包含C/D类,就像C#代码一样?
我正在编写一个应用程序,我需要以极低的处理器速度运行.应用程序在整个运行过程中以创造性的方式创建和销毁内存,并且工作得很好.什么编译器优化发生,所以我可以尝试构建到那个?
另一个技巧是CLR处理数组比列表快得多,所以如果你需要处理List中的大量元素,你可能最好调用ToArray()并处理它而不是一次又一次地调用ElementAt() .
在MonoTouch下,以下代码行编译,但生成InvalidProgramException:
var bytes = new byte[,]{};
Run Code Online (Sandbox Code Playgroud)
System.InvalidProgramException
Invalid IL code in Foo: IL_0038: newobj 0x0a000012
但是,以下内容在运行时不会失败:
var bytes = new byte[,]{{}};
Run Code Online (Sandbox Code Playgroud)
我使用第二个表达式很好.但是,第一个有什么问题吗?如果是这样,它不应该编译失败吗?
il ×10
c# ×6
.net ×3
cil ×2
mono ×2
attributes ×1
blob ×1
clr ×1
csc ×1
interop ×1
namespaces ×1
optimization ×1
ref ×1
xamarin.ios ×1