我正在用C#编写一个小编译器,并计划使用.Net平台生成IL指令System.Reflection.Emit.我的问题是,建议System.Reflection.Emit用于为生产编译器生成IL.
如果不建议System.Reflection.Emit用于为生产编译器生成IL,我们是否有用于此目的的替代库/工具?
我想为多线程应用程序生成IL.作为第一步,我编写了一个简单的应用程序并进行了检查,使用ILSpy生成了IL.
public class ThreadTesting
{
public static void Main()
{
Thread thread = new Thread(() => Print("Hello from t!"));
thread.Start();
}
public static void Print(string message)
{
Console.WriteLine(message);
}
}
Run Code Online (Sandbox Code Playgroud)
.method public hidebysig static
void Main () cil managed
{
// Method begins at RVA 0x2060
// Code size 46 (0x2e)
.maxstack 3
.entrypoint
.locals init (
[0] class [mscorlib]System.Threading.Thread
)
IL_0000: nop
IL_0001: ldsfld class [mscorlib]System.Threading.ThreadStart ThreadTesting::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0006: brtrue.s IL_001b
IL_0008: ldnull
IL_0009: ldftn void ThreadTesting::'<Main>b__0'()
IL_000f: newobj instance …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Mono.Cecil 重现以下 IL:
call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [System]System.ComponentModel.PropertyChangedEventHandler>(!!0&, !!0, !!0)
Run Code Online (Sandbox Code Playgroud)
当我使用 Mono.Cecil 检查这个 IL 时,我看到指令的操作数是一个 GenericInstanceMethod,它包含一个 MethodReference 类型的 ElementMethod。此 MethodReference 又具有 GenericParameter 类型的返回类型。
我想手动创建相同的对象,但似乎达到了 catch-22。要创建 GenericParameter,我需要一个 IGenericParameterOwner,它似乎与上面的 MethodReference 完全相同。所以我想将 MethodReference 传递给 GenericParameter 构造函数。但是,如果没有返回类型的 TypeReference,我也无法创建 MethodReference,我认为它应该是 GenericParameter。
我该如何解决?我误解了什么?
我有新问题.我的代码:
.method public static void Main() cil managed
{
.entrypoint
// Code size 3 (0x3)
.maxstack 1
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
C#代码:
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
我通过System.Reflection和System.Reflection.Emit类生成此代码.有谁知道为什么这不起作用?请帮忙.

一个小问题 - 我应该生成构造函数吗?
我有一个应用程序,其中有一个采用 PropertyInfo 参数的方法,并且希望从 IL 调用此方法。例如,对于采用 MethodInfo 的类似方法,我可以创建一个采用RuntimeMethodHandle 的中间方法并使用GetMethodFromHandle。然后 IL 可以使用Ldtoken来传递句柄。
但是,似乎没有等效的属性元数据标记。我可以理解为什么会出现这种情况(因为属性实际上只是将方法捆绑在一起的一种方式,并且永远不会从 IL 中“调用”),但肯定存在与该类型关联的属性元数据。我可以在发出时访问此属性元数据,因此我想要一种能够直接传递此属性的方法,而不必在运行时通过名称诉诸反射(即,向 GetProperty 发出反射调用,并采用将在以下位置执行的字符串)运行时。)有办法做到这一点吗?
根据评论中的请求,这是应用程序:
我正在创建一个适配器类,它通过属性公开属性引用作为其组件位bool this[int index]。我的应用程序将 PLC 代码编译为 .NET 程序集,因此我尝试创建诊断访问器,该访问器近似于 PLC 提供的简单按位访问(您在其中写入MyTag.2以指示 tag 的位 2 MyTag)。此语法不能用于C# 的消耗,但这PLC.GetBits().MyTag[2]是一个合理的近似值。
我最初的方法是使用 PropertyInfo 实现的(这就是我遇到此问题的方式),但我当然可以通过将 PropertyInfo 中的适用元数据作为多个参数传递来解决此问题。我主要只是好奇是否可以直接传递 PropertyInfo,因为我以前从未遇到过这种情况。
是否可以编写通用CIL指令,将任何类型的实例(值和引用)转换为System.String?特别是,我对Mono.Cecil代码很感兴趣,它会将这些指令注入到方法中.
分析一个通用方法我想出了这些Mono.Cecil调用:(它应该将第i个方法参数转换为字符串)
System.Reflection.MethodInfo to_string_method_info = typeof( System.Object ).GetMethod( "ToString" );
Mono.Cecil.MethodReference to_string_reference = injectible_assembly.MainModule.Import( to_string_method_info );
Mono.Cecil.TypeReference argument_type = method_definition.Parameters[ i ].ParameterType;
method_definition.Body.Instructions.Add( processor.Create( Mono.Cecil.Cil.OpCodes.Constrained, argument_type ) );
method_definition.Body.Instructions.Add( processor.Create( Mono.Cecil.Cil.OpCodes.Callvirt, to_string_reference ) );
Run Code Online (Sandbox Code Playgroud)
但是,在调试时,我从注入的方法中获得"JIT编译器遇到内部限制"的异常.
在Jon Skeet的"C#in depth"中,我正在阅读(第511页):
所有数组都派生自System.Array,它们是CLR中唯一直接支持的集合(我的重点).
我想知道这意味着什么,特别是与没有这种支持的类型有关.在解释IL时,所有没有此类支持的类型是否都是由CLR所做的类型组合而成的?CLR没有"知道"没有这种支持的类型吗?
也在p.本书512:
C#编译器以多种方式内置了对数组的支持.
这在某种程度上与Array类型在CLR中的直接支持有关,还是这两个单独的东西?
这是我的代码:
private void ModifyMethods()
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
using System;
namespace ToIL
{
public class Class1
{
public void Write()
{
Console.WriteLine(""Hello"");
}
}
}");
string assemblyName = System.IO.Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
CSharpCompilation compilation = CSharpCompilation.Create( assemblyName, syntaxTrees: new[] { syntaxTree }, references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
Mono.Cecil.AssemblyDefinition asm = null;
using (var ms = new MemoryStream())
{
var emitResult = compilation.Emit(ms);
if (emitResult.Success)
{
ms.Seek(0, SeekOrigin.Begin);
asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(ms);
}
}
var …Run Code Online (Sandbox Code Playgroud) 假设我有一个需要优化但同时易于调试的代码.因此,我会为我使用的每个值分配一个字符串.该字符串是否会造成重大性能损失,或者它是否变成了一个从string.Intern在JIT/ AOTcompilation中获得的常量引用,从而变成一条简单的指令?
例:
在IL中它会是ldstr "gazilion lines".
它是在JIT/AOT编译期间变成类似的东西ldsflda string.InternCache.ID_0000647516166
并被const string ID_0000647516166 = "gazilion lines";
添加到string.InternCache?
是的,我理论上可以查看https://github.com/mono/mono但我不知道如何找到它.
是的,我正在混合使用CIL,C#以及编译的CIL,但是你明白了.
为ldstr保证是O(1)?
是的,它是CLR的"实现细节",但如果以这种方式进行优化,那将是有意义的.
我真的需要关心可以发出.s指令的地方吗?或者它只会影响尺寸,但真正的性能会是一样的吗?
生成的dll也将在AOT平台上使用.有.s和没有IL的结果AOT-ed dll是否相同?
我的意思是br.s,ldloca.s等.