C#调用
Math.Pow(2,3);
Run Code Online (Sandbox Code Playgroud)
在ILDASM中:
ldc.r8 2.
ldc.r8 3.
call float64[mscorlib]System.Math::Pow(float64, float64)
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我如何通过ILGenerator发出该调用语句吗?谢谢.
众所周知,字符串是隐式实例化的,这意味着我们不必使用new它来获取对象的对象的引用.
因此,我一直认为框架正在处理这个问题,因此如果我这样做,我会得到相同的IL:
String first = new String(new char[] {'a'});
string second = "a";
Run Code Online (Sandbox Code Playgroud)
然而,似乎第一行是使用newobj instance void [mscorlib]System.String::.ctor(char[])
和第二行完成的ldstr "a".
那么为了获得一个字符串引用,ldstr内部调用newobj,我在哪里可以看到规范/细节来支持它?
我刚开始看一下IL,我很好奇我的尝试(如下所示)从编译器输出中删除多余的代码有任何意想不到的副作用.
关于结果的几个问题:
原始C#代码:
class Program {
public static int Main() {
return Add(1, 2);
}
public static int Add(int a, int b) {
return a + b;
}
}
Run Code Online (Sandbox Code Playgroud)
csc.exe用ildasm.exe(原始)编译和拆解它:
.method public hidebysig static int32 Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: call int32 Program::Add(int32, int32)
IL_0008: stloc.0
IL_0009: br.s IL_000b
IL_000b: ldloc.0
IL_000c: ret
}
.method public hidebysig static int32 Add(int32 a, …Run Code Online (Sandbox Code Playgroud) 我需要找出一个通用结构的大小(我不能像sizeof(T)或使用Marshal.SizeOf(...)0>给我一个错误)
所以我写道:
public static class HelperMethods
{
static HelperMethods()
{
SizeOfType = createSizeOfFunc();
}
public static int SizeOf<T>()
{
return SizeOfType(typeof(T));
}
public static readonly Func<Type, int> SizeOfType = null;
private static Func<Type, int> createSizeOfFunc()
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { typeof(Type) });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Sizeof); //needs to be il.Emit(OpCodes.Sizeof, typeof(something))
il.Emit(OpCodes.Ret);
var func = (Func<Type, int>)dm.CreateDelegate(typeof(Func<Type, int>));
return func;
}
}
Run Code Online (Sandbox Code Playgroud)
一个不同之处是il.Emit(OpCodes.Sizeof)需要一个参数,在创建方法(SizeOfType)时我无法传递它.如何使用IL将堆栈中的参数传递给il.Emit(OpCodes.Sizeof)?(或者是一个不同的解决方案,但我想缓存一个函数(委托)而不是第二个答案中提出的结果)
我正在使用Unity3D for Mobile的免费版本,它不允许我System.Net.Sockets在移动设备上使用命名空间.问题是我正在使用.dll引用的编译库(即IKVM)System.Net.Sockets.我实际上并没有在IKVM中使用引用该引用的类System.Net.Sockets,因此我没有购买$ 3000 Unity Pro移动许可证,而是创建了一个Sockets名为的命名空间的存根库,dudeprgm.Net.Sockets它只是用存根替换了所有的类和方法(我这样做了Mono源代码).
我需要将System.Net.Sockets.*我的dll中的所有引用替换为dudeprgm.Net.Sockets.*.我知道这样的事情是可能的并且由其他人完成(参见下面的编辑,在页面底部).我想知道自己该怎么做.
我能够使用Mono.Cecil提出以下代码.
它遍历所有IL指令,检查操作数是否为a InlineType,然后检查内联类型是否属于其中System.Net.Sockets,然后将其重命名为dudeprgm.Net.Sockets并写入.**我不确定这是否是在Mono.Cecil中进行"查找和替换"的正确方法.问题是,这并没有抓住所有Sockets用法(见下文).
private static AssemblyDefinition stubsAssembly;
static void Main(string[] args) {
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(args[0]);
stubsAssembly = AssemblyDefinition.ReadAssembly("Socket Stubs.dll");
// ...
// Call ProcessSockets on everything
// ...
asm.Write(args[1]);
}
/*
* This will be run on every property, constructor and method …Run Code Online (Sandbox Code Playgroud) double在没有抛出异常的情况下,在IL中检测值是否为有限值(NaN和正/负无穷大)的最快方法是什么?
我正在考虑以下方法(仅为了方便读者使用c#表示法,在我的项目中,我使用的是IL):
!double.IsNaN(x) && !double.IsInfinity(x) - 最明显的,也可能是最慢的,因为涉及2个方法调用.
(*(((long*) &x)) & 0x7fffffffffffffffL) < 0x7ff0000000000000L
或在IL:
ldloca x
conv.u
ldind.i8
ldc.i8 0x7fffffffffffffff
and
ldc.i8 0x7ff0000000000000
clt
Run Code Online (Sandbox Code Playgroud)
我对第二种方法的问题是:
根据我的研究,这应该精确地确定任何给定是否x是有限的.这是真的?
它是解决IL中任务的最佳方式(性能方面),还是有更好(更快)的解决方案?
PS我非常感谢建议运行我自己的基准并找出答案,并且肯定会这样做.只是想到也许有人已经有类似的问题,并知道答案.PPS是的,我意识到我们在这里谈论的是纳秒,是的,它们对我的具体情况很重要
这段代码
Regex regex = new Regex("blah", RegexOptions.Singleline & RegexOptions.IgnoreCase);
Run Code Online (Sandbox Code Playgroud)
编译后在ILSpy中看起来像这样:
Regex regex = new Regex("blah", RegexOptions.None);
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况,并且它是正则表达式在.Net 3.5中不匹配的原因吗?在4.5它工作.
有了C#6表达身体的成员,我可以写:
public string FullName => $"{_firstName} {_lastName}";
我可以写:
static void Print(string message) => Console.WriteLine(message);
在第一个实例中,表达式返回一些东西.在第二个,它没有.
这里发生了什么,以确定如何"行动"而不需要任何额外的语法?或者它只是在编译期间查看方法签名的情况?
在不知道发生了什么的情况下,我不会把事情留给"正常工作".
我意识到已经被问及并回答Visual Studio不支持CIL/MSIL项目.该MSBuildContrib项目有ILASM任务,它允许您编译IL文件在制作的时候.
关于如何使用此任务的示例,Google搜索结果为空.
是否有任何使用ILASM作为Visual Studio解决方案的一部分的示例?我意识到#develope和ILIDE支持CIL ......这里的目标是编译一些CIL文件作为Visual Studio解决方案的一部分.
我有一个递归函数emit : Map<string,LocalBuilder> -> exp -> unit,其中il : ILGenerator是全局的功能,exp是代表与情况的类型检查解析的语言判别工会InstanceCall of exp * MethodInfo * exp list * Type和Type是一个属性exp代表表达的类型.
在下面的片段中,我试图为实例调用发出IL操作码,其中instance.Type可能是也可能不是ValueType.所以我理解我可以OpCodes.Constrained灵活高效地对引用,值和枚举类型进行虚拟调用.我是Reflection.Emit和机器语言的新手,因此理解链接文档OpCodes.Constrained并不适合我.
这是我的尝试,但结果是VerificationException"操作可能会破坏运行时的稳定性.":
let rec emit lenv ast =
match ast with
...
| InstanceCall(instance,methodInfo,args,_) ->
instance::args |> List.iter (emit lenv)
il.Emit(OpCodes.Constrained, instance.Type)
il.Emit(OpCodes.Callvirt, methodInfo)
...
Run Code Online (Sandbox Code Playgroud)
查看文档,我认为关键可能是"托管指针,ptr,被推入堆栈.ptr的类型必须是thisType的托管指针(&).请注意,这与未加前缀的情况不同callvirt指令,它需要thisType的引用."
更新
谢谢@Tomas和@desco,我现在知道何时使用OpCodes.Constrained(instance.Type是一个ValueType,但是methodInfo.DeclaringType是一个引用类型).
但事实证明我还不需要考虑那个案例,而我真正的问题是堆栈上的实例参数:我花了6个小时才知道它需要一个地址而不是值(看DLR源码)代码给了我线索,然后在一个简单的C#程序上使用ilasm.exe说清楚了).
这是我的最终工作版本:
let rec emit lenv …Run Code Online (Sandbox Code Playgroud)