如何从 il 生成器调用 Action<string, bool>
How to call Action<string, bool> from il generator
在此示例代码中,我试图从 il 生成器调用匿名操作。我不确定是否以及如何加载对委托的引用以及如何调用它。
如果 OnFunctionCall
是静态方法而不是 属性.
,我可以做到
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("Example");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Action<string, bool> onFunctionCall)
where TType : class
{
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Emit some code that invoke unmanaged function ...
// loading the first string argument
il.Emit(OpCodes.Ldstr, method.Name);
// not sure here how to load boolean value to the stack
il.Emit(OpCodes.Ldc_I4_0);
// this line doesn't work
// example two has no idea about ExampleOne
// is it possible to load the reference of the Action<string, bool> to the stack and call it ?
il.Emit(OpCodes.Call, onFunctionCall.Method);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
=> ExampleTwo
.CreateDelegate<TestDelegate>(ExampleOne.OnFunctionCall)
.Invoke();
}
您必须传递存储要调用的委托的信息。方便的方法是接受 MemberExpression
,否则接受 MemberInfo
也可以。看看你修改后的代码:
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("OnFunctionCall");
public static Action<string, bool> OnFunctionCallField
= (message, flag) => Console.WriteLine("OnFunctionCallField");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Expression<Func<object>> expression)
where TType : class
{
var body = expression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(nameof(expression));
}
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Get typed invoke method and
// call getter or load field
MethodInfo invoke;
if (body.Member is PropertyInfo pi)
{
invoke = pi.PropertyType.GetMethod("Invoke");
il.Emit(OpCodes.Call, pi.GetGetMethod());
}
else if (body.Member is FieldInfo fi)
{
invoke = fi.FieldType.GetMethod("Invoke");
il.Emit(OpCodes.Ldsfld, fi);
}
else
{
throw new ArgumentException(nameof(expression));
}
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Callvirt, invoke);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
{
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCall)
.Invoke();
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCallField)
.Invoke();
Console.ReadLine();
}
}
.Net Core 2.0 上的代码是 运行。
在此示例代码中,我试图从 il 生成器调用匿名操作。我不确定是否以及如何加载对委托的引用以及如何调用它。
如果 OnFunctionCall
是静态方法而不是 属性.
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("Example");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Action<string, bool> onFunctionCall)
where TType : class
{
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Emit some code that invoke unmanaged function ...
// loading the first string argument
il.Emit(OpCodes.Ldstr, method.Name);
// not sure here how to load boolean value to the stack
il.Emit(OpCodes.Ldc_I4_0);
// this line doesn't work
// example two has no idea about ExampleOne
// is it possible to load the reference of the Action<string, bool> to the stack and call it ?
il.Emit(OpCodes.Call, onFunctionCall.Method);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
=> ExampleTwo
.CreateDelegate<TestDelegate>(ExampleOne.OnFunctionCall)
.Invoke();
}
您必须传递存储要调用的委托的信息。方便的方法是接受 MemberExpression
,否则接受 MemberInfo
也可以。看看你修改后的代码:
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("OnFunctionCall");
public static Action<string, bool> OnFunctionCallField
= (message, flag) => Console.WriteLine("OnFunctionCallField");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Expression<Func<object>> expression)
where TType : class
{
var body = expression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(nameof(expression));
}
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Get typed invoke method and
// call getter or load field
MethodInfo invoke;
if (body.Member is PropertyInfo pi)
{
invoke = pi.PropertyType.GetMethod("Invoke");
il.Emit(OpCodes.Call, pi.GetGetMethod());
}
else if (body.Member is FieldInfo fi)
{
invoke = fi.FieldType.GetMethod("Invoke");
il.Emit(OpCodes.Ldsfld, fi);
}
else
{
throw new ArgumentException(nameof(expression));
}
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Callvirt, invoke);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
{
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCall)
.Invoke();
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCallField)
.Invoke();
Console.ReadLine();
}
}
.Net Core 2.0 上的代码是 运行。