C# 在运行时自动生成方法回调?
C# Automatic generate method callbacks on runtime?
我想将运行时方法绑定到 class 方法(如果我调用运行时方法,它必须调用我的 class 方法,有或没有参数和 return 值).
如果我没有在 invoke 方法和 Callback 方法上设置参数,我的代码就可以工作,但是,如果我设置了参数,我得到了错误:"give error Parameter count mismatch.":我该如何修复它?
public class RunNow
{
public void Run(string hoo)
{
}
public void Callback(string ali)
{
Console.WriteLine("yessss");
}
}
class Program
{
static void Main(string[] args)
{
RunNow run = new CSMethodInjection.RunNow();
var methodToCall = run.GetType().GetMethod("Callback");
var t = GenerateType(run.GetType().Name, methodToCall);
if (t != null)
{
object o = Activator.CreateInstance(t);
MethodInfo helloWorld = t.GetMethod(methodToCall.Name);
if (helloWorld != null)
{
helloWorld.Invoke(o, new object[] { "aaaaa" });//give error Parameter count mismatch.
}
}
Console.ReadLine();
}
static Type GenerateType(string className, MethodInfo toCall)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
AssemblyName assemName = new AssemblyName();
assemName.Name = "InjectionAssembly";
AssemblyBuilder assemBuilder = currentDomain.DefineDynamicAssembly(assemName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemBuilder.DefineDynamicModule("InjectionModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod(toCall.Name, MethodAttributes.Public, null, null);
List<Type> parameters = new List<Type>();
foreach (var item in toCall.GetParameters())
{
parameters.Add(item.ParameterType);
var pBuilder = methodBuilder.DefineParameter(item.Position, item.Attributes, item.Name);
}
if (parameters.Count > 0)
methodBuilder.SetParameters(parameters.ToArray());
methodBuilder.SetReturnType(toCall.ReturnType);
ILGenerator msilG = methodBuilder.GetILGenerator();
msilG.Emit(OpCodes.Ldarg_0);
msilG.Emit(OpCodes.Call, toCall);
msilG.Emit(OpCodes.Ret);
return typeBuilder.CreateType();
}
}
要修复计数错误,您可以删除或注释掉错误填充参数列表的 foreach 并 改为
MethodBuilder methodBuilder = typeBuilder.DefineMethod(toCall.Name,
MethodAttributes.Public,
toCall.ReturnType,
toCall.GetParameters().Select(x => x.ParameterType).ToArray());
那你的生成器还有其他问题,
我们可以通过以下方式简化它
ILGenerator msilG = methodBuilder.GetILGenerator();
msilG.EmitWriteLine("Hello World"); // or much better see below
msilG.Emit(OpCodes.Ret);
return typeBuilder.CreateType();
或者,好多了,用
替换上面的msilG.EmitWriteLine("Hello World");
msilG.Emit(OpCodes.Ldarg_0);
msilG.Emit(OpCodes.Ldarg_1); // it's cool, isn't it?
msilG.Emit(OpCodes.Call, toCall);
最后你也可以调整回调了;)
public void Callback(string ali)
{
Console.WriteLine(ali); // let me see "aaaaa"
}
我想将运行时方法绑定到 class 方法(如果我调用运行时方法,它必须调用我的 class 方法,有或没有参数和 return 值).
如果我没有在 invoke 方法和 Callback 方法上设置参数,我的代码就可以工作,但是,如果我设置了参数,我得到了错误:"give error Parameter count mismatch.":我该如何修复它?
public class RunNow
{
public void Run(string hoo)
{
}
public void Callback(string ali)
{
Console.WriteLine("yessss");
}
}
class Program
{
static void Main(string[] args)
{
RunNow run = new CSMethodInjection.RunNow();
var methodToCall = run.GetType().GetMethod("Callback");
var t = GenerateType(run.GetType().Name, methodToCall);
if (t != null)
{
object o = Activator.CreateInstance(t);
MethodInfo helloWorld = t.GetMethod(methodToCall.Name);
if (helloWorld != null)
{
helloWorld.Invoke(o, new object[] { "aaaaa" });//give error Parameter count mismatch.
}
}
Console.ReadLine();
}
static Type GenerateType(string className, MethodInfo toCall)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
AssemblyName assemName = new AssemblyName();
assemName.Name = "InjectionAssembly";
AssemblyBuilder assemBuilder = currentDomain.DefineDynamicAssembly(assemName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemBuilder.DefineDynamicModule("InjectionModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod(toCall.Name, MethodAttributes.Public, null, null);
List<Type> parameters = new List<Type>();
foreach (var item in toCall.GetParameters())
{
parameters.Add(item.ParameterType);
var pBuilder = methodBuilder.DefineParameter(item.Position, item.Attributes, item.Name);
}
if (parameters.Count > 0)
methodBuilder.SetParameters(parameters.ToArray());
methodBuilder.SetReturnType(toCall.ReturnType);
ILGenerator msilG = methodBuilder.GetILGenerator();
msilG.Emit(OpCodes.Ldarg_0);
msilG.Emit(OpCodes.Call, toCall);
msilG.Emit(OpCodes.Ret);
return typeBuilder.CreateType();
}
}
要修复计数错误,您可以删除或注释掉错误填充参数列表的 foreach 并 改为
MethodBuilder methodBuilder = typeBuilder.DefineMethod(toCall.Name,
MethodAttributes.Public,
toCall.ReturnType,
toCall.GetParameters().Select(x => x.ParameterType).ToArray());
那你的生成器还有其他问题, 我们可以通过以下方式简化它
ILGenerator msilG = methodBuilder.GetILGenerator();
msilG.EmitWriteLine("Hello World"); // or much better see below
msilG.Emit(OpCodes.Ret);
return typeBuilder.CreateType();
或者,好多了,用
替换上面的msilG.EmitWriteLine("Hello World");
msilG.Emit(OpCodes.Ldarg_0);
msilG.Emit(OpCodes.Ldarg_1); // it's cool, isn't it?
msilG.Emit(OpCodes.Call, toCall);
最后你也可以调整回调了;)
public void Callback(string ali)
{
Console.WriteLine(ali); // let me see "aaaaa"
}