我正在玩Reflection.Emit并找到关于这个很少用的东西EmitCalli
.好奇,我想知道它是否与常规方法调用有任何不同,所以我掀起了下面的代码:
using System;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Security;
[SuppressUnmanagedCodeSecurity]
static class Program
{
const long COUNT = 1 << 22;
static readonly byte[] multiply = IntPtr.Size == sizeof(int) ?
new byte[] { 0x8B, 0x44, 0x24, 0x04, 0x0F, 0xAF, 0x44, 0x24, 0x08, 0xC3 }
: new byte[] { 0x0f, 0xaf, 0xca, 0x8b, 0xc1, 0xc3 };
static void Main()
{
var handle = GCHandle.Alloc(multiply, GCHandleType.Pinned);
try
{
//Make the native method executable
uint old;
VirtualProtect(handle.AddrOfPinnedObject(),
(IntPtr)multiply.Length, 0x40, …
Run Code Online (Sandbox Code Playgroud) 想象一下,我们有一个可变的struct
(是的,不要开始):
public struct MutableStruct
{
public int Foo { get; set; }
public override string ToString()
{
return Foo.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
使用反射,我们可以获取一个盒装实例,struct
并在框内变异:
// this is basically what we want to emulate
object obj = new MutableStruct { Foo = 123 };
obj.GetType().GetProperty("Foo").SetValue(obj, 456);
System.Console.WriteLine(obj); // "456"
Run Code Online (Sandbox Code Playgroud)
我会喜欢做的是写一些IL可以做同样的,因为这-但速度更快.我是一个元编程迷; p
拆箱 - 任何值并使用常规IL改变值是微不足道的 - 但是你不能只是在之后调用它,因为这将创建一个不同的框.我猜我们需要做的是将它复制到现有的盒子上.我已经调查了ldobj
/ stobj
,但那些似乎没有做到这一点(除非我遗漏了什么).
那么:是否存在这样做的机制?或者我必须限制自己反思以执行盒装struct
s 的就地更新?
换句话说:什么... evil goes here...
?
var method = …
Run Code Online (Sandbox Code Playgroud) 我正在考虑将第三方库移植到.NET for Windows Store应用程序.该库通过调用ILGenerator.Emit方法重载过度使用System.Reflection.Emit.OpCodes.
在.NET for Windows Store Apps API中,包含了OpCode
结构和OpCodes
类,但没有ILGenerator
类,并且我已经找不到替换.
我显然失去了一些东西,但:没有ILGenerator
一流的,什么是包括的目的System.Reflection.Emit.OpCode
和OpCodes
在.NET的Windows Store应用程序的API?
我通过使用生成类型的包装器System.Reflection.Emit
.有一次,原始对象可能会在access(FaultException
)上抛出一个错误,错误应该由我try { } catch (Exception e) { }
实现的错误捕获,但事实并非如此.
代码由ILSpy正确显示.
try
{
if (original.Station != null)
{
if (objectDictionary.ContainsKey(original.Station))
{
this.Station = (objectDictionary[original.Station] as StationWrapper);
}
else
{
this.Station = new StationWrapper(original.Station, objectDictionary);
}
}
}
catch (Exception arg_6D_0)
{
ReportManager.Log(arg_6D_0);
}
Run Code Online (Sandbox Code Playgroud)
这是组装生成的代码.
Label ex = il.BeginExceptionBlock();
....
// Exception block end
il.Emit(OpCodes.Leave, ex);
il.BeginCatchBlock(typeof(Exception));
il.Emit(OpCodes.Call, ReportManager_Log);
il.EndExceptionBlock();
Run Code Online (Sandbox Code Playgroud)
例外是被用户代码捕获而不是被IL-Code捕获.
在这里删除了客户的一些名称空间.写行已在最后几分钟添加.
.try
{
IL_0019: ldarg.1
IL_001a: call instance class [...]...Station [...]...StationBase::get_Station() …
Run Code Online (Sandbox Code Playgroud) 我有这样的代码,发出一些IL
调用指令string.IndexOf
一对null
对象:
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
"Foo",
MethodAttributes.Public,
typeof(void), Array.Empty<Type>());
var methodInfo = typeof(string).GetMethod("IndexOf", new[] {typeof(char)});
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldnull);
ilGenerator.Emit(OpCodes.Ldc_I4_S, 120);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
这是生成的IL
代码:
.method public instance int32 Foo() cil managed
{
// Code size 12 (0xc)
.maxstack 2
IL_0000: ldnull
IL_0001: ldc.i4.s 120
IL_0003: nop
IL_0004: nop
IL_0005: nop
IL_0006: call instance int32 [mscorlib]System.String::IndexOf(char)
IL_000b: ret
} // end of method MyDynamicType::Foo
Run Code Online (Sandbox Code Playgroud)
如您所见,nop
指令前有三条call
指令.
首先我考虑了Debug/Release构建,但这不是编译器生成的代码,我发出了原始的IL代码,并希望看到它原样.
所以我的问题是为什么 …
我正在尝试在C#中使用Reflection.Emit来发出一个using (x) { ... }
块.
在我处于代码中的时候,我需要获取堆栈的当前顶部,这是一个实现IDisposable的对象,将其存储在局部变量中,在该变量上实现一个使用块,然后在其中添加更多代码(我可以处理最后一部分.)
这是我尝试编译并在Reflector中查看的C#代码示例:
public void Test()
{
TestDisposable disposable = new TestDisposable();
using (disposable)
{
throw new Exception("Test");
}
}
Run Code Online (Sandbox Code Playgroud)
这在Reflector中看起来像这样:
.method public hidebysig instance void Test() cil managed
{
.maxstack 2
.locals init (
[0] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable disposable,
[1] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable CS$3$0000,
[2] bool CS$4$0001)
L_0000: nop
L_0001: newobj instance void LVK.Reflection.Tests.UsingConstructTests/TestDisposable::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: stloc.1
L_0009: nop
L_000a: ldstr "Test"
L_000f: newobj instance void [mscorlib]System.Exception::.ctor(string)
L_0014: throw
L_0015: ldloc.1
L_0016: …
Run Code Online (Sandbox Code Playgroud) 我需要动态创建一个类.大多数工作正常,但我坚持生成构造函数.
AssemblyBuilder _assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyBuilder"), AssemblyBuilderAccess.Run);
ModuleBuilder _moduleBuilder = _assemblyBuilder.DefineDynamicModule("MyModule");
public static object GetInstance<TSource, TEventArgs>(this TSource source, string eventName)
where TSource : class
{
var typeName = "MyTypeName";
var typeBuilder = _moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public);
// create type like class MyClass : GenericType<MyClass, TSource, TEventArgs>
var baseNotGenericType = typeof(GenericType<,,>);
var baseType = baseNotGenericType.MakeGenericType(typeBuilder, typeof(TSource), typeof(TEventArgs));
typeBuilder.SetParent(baseType);
// the base class contains one constructor with string as param
var baseCtor = baseNotGenericType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string) }, null); …
Run Code Online (Sandbox Code Playgroud) 我现在使用System.Reflection.Emit一段时间了,发现它(谁没有?)像容易出错一样痛苦.
你知道IL Generator周围是否有一个好的包装器,我可以依赖它以比直接使用SRE更安全,更容易的方式发出IL吗?
编辑:
我知道操纵表达树比直接发射IL更容易和更安全,但它们现在也有一些限制.我不能创建代码块,使用循环,声明和使用几个本地,等等.我们需要等到.NET 4出来:)
此外,我正在处理已经依赖于SRE的代码库.
显然,ILGenerator会做我需要的一切.但是在操纵它时我会感激更多的帮助.当我指的是一个非常低级别的ILGenerator包装器时,我想到的东西可以提供如下方法:
// Performs a virtual or direct call on the method, depending if it is a
// virtual or a static one.
Call(MethodInfo methodInfo)
// Pushes the default value of the type on the stack, then emit
// the Ret opcode.
ReturnDefault(Type type)
// Test the object type to emit the corresponding push
// opcode (Ldstr, Ldc_I*, Ldc_R*, etc.)
LoadConstant(object o)
Run Code Online (Sandbox Code Playgroud)
这真的是3个天真的例子,但它足以证明我的期望.我们可以看到它作为一组扩展方法,但是在RunSharp中支持条件语句和循环可能会很好.实际上,RunSharp与我想要的非常接近,但它过多地抽象了ILGenerator并且没有公开它的所有功能.
我不记得在哪里,但我已经在开源项目中看到过这样的帮手.
给出以下代码:
using System;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Reflection;
namespace ConsoleApplication1
{
class A
{
public int Do(int n)
{
return n;
}
}
public delegate int DoDelegate();
class Program
{
public static void Main(string[] args)
{
A a = new A();
Stopwatch stopwatch = Stopwatch.StartNew();
int s = 0;
for (int i = 0; i < 100000000; i++)
{
s += a.Do(i);
}
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(s);
DynamicMethod dm = new DynamicMethod("Echo", typeof(int), new Type[] { typeof(int) }, true);
ILGenerator il …
Run Code Online (Sandbox Code Playgroud) 假设我们有一个接口:
public interface ICalculator
{
decimal Calculate(decimal x, decimal y);
}
Run Code Online (Sandbox Code Playgroud)
计算逻辑是用javascript(实际上是TypeScript)代码实现的,我们想用Reflection.Emit动态创建跟随实现,所以我们可以用C#实现共享单元测试:
public class Calculator : ICalculator
{
private ScriptEngine ScriptEngine;
public Calculator(ScriptEngine scriptEngine, string jsFileFullPath)
{
this.ScriptEngine = scriptEngine;
var jsFileContent = File.ReadAllText(jsFileFullPath);
this.ScriptEngine.Execute(jsFileContent);
}
public decimal Calculate(decimal x, decimal y)
{
string script = @"
var rf1013 = new TotalTaxation.TaxformCalculation.RF1013({0},{1});
rf1013.Calculate();
var result = rf1013.RF1013Sum;
";
this.ScriptEngine.Evaluate(string.Format(script, x, y));
var result = this.ScriptEngine.Evaluate("result");
return Convert.ToDecimal(result);
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以从IL DASM获得IL:
.class public auto ansi beforefieldinit Calculator
extends …
Run Code Online (Sandbox Code Playgroud)