使用 Reflection.Emit 调用 AutoGenerated class 的方法
Invoking method of AutoGenerated class with Reflection.Emit
你好,我想知道如何在不使用 reflexion.As 的情况下调用 class 的方法,你可以看到我正在使用生成器 class Weaver
(使用 Reflection.Emit
),returns a Func<object>
(我无法指定动态类型)。当我检索实例时,我将如何调用其中一个方法,特别是 DoInt
?
我想要什么AutoGenerate
class Gen {
public Gen() {
}
public int DoInt(int a,string b) {
int rez=a+b.count();
return 3;
}
}
发电机class
class Weaver {
public static Func<object> Weave() {
var weaver = new Weaver();
weaver.Run();
return weaver.output as Func<object>;
}
private AssemblyBuilder assemblyBuilder;
private ModuleBuilder moduleBuilder;
private TypeBuilder typebuilder;
private object output;
public Weaver() {
}
private void Run() {
this.DefineAssembly();
this.DefineModule();
this.DefineClass();
this.DefineMethod();
this.Wrap();
}
private void DefineAssembly() {
AssemblyName name = new AssemblyName("Coda");
AppDomain domain = AppDomain.CurrentDomain;
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
}
private void DefineModule() {
this.moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyBuilder.FullName + ".dll");
}
private void DefineClass() {
this.typebuilder = this.moduleBuilder.DefineType("A",
TypeAttributes.Abstract|TypeAttributes.Public|TypeAttributes.BeforeFieldInit|TypeAttributes.AnsiClass|TypeAttributes.AutoClass,
typeof(object), null );
}
private void DefineMethod() {
MethodBuilder methodBuilder = this.typebuilder.DefineMethod("DoInt", MethodAttributes.Public, typeof(int), new[] { typeof(int), typeof(string) });
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Call, typeof(Enumerable).GetMethod("Count", BindingFlags.Static), null);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
}
private void Wrap() {
Type type = typebuilder.CreateType();
this.output = Activator.CreateInstance(type);
}
}
主要
static void Main(string[] args)
{
string t = "astada";
var c = Weaver.Weave();
var result=c.GetType().GetMethod("DoInt").Invoke(null, new object[] { 3, "mystring" }); //should be 3+ "mystring".Count()
Console.ReadLine();
}
要使其正常工作,您首先需要修复 Weaver
,因为它包含几个错误:
private void DefineClass()
{
// TypeAttributes.Abstract should not be used here as we want to create
// type that can be instantiated
this.typebuilder = this.moduleBuilder.DefineType(
"A",
TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
typeof(object),
null);
}
private void DefineMethod()
{
MethodBuilder methodBuilder = this.typebuilder.DefineMethod(
"DoInt",
MethodAttributes.Public,
typeof(int), new[] { typeof(int), typeof(string) });
var il = methodBuilder.GetILGenerator();
// Arguments are counted from zero. For instance methods, argument0 is
// reserved for 'this' instance. So to get "string" argument (second "real" argument),
// you need Ldarg_2
il.Emit(OpCodes.Ldarg_2);
// You cannot get MethodInfo for "Count" method with simple GetMethod(),
// since it is generic method with several overloads.
var countMethodInfo = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.Name == "Count")
.Where(m => m.GetParameters().Length == 1)
.Single()
//We want Count<char>() method, because we want to count characters on string (casted to IEnumerable<char>).
.MakeGenericMethod(typeof(char));
il.EmitCall(OpCodes.Call, countMethodInfo, null);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
}
public static object Weave()
{
var weaver = new Weaver();
weaver.Run();
// return weaver.output as Func<object>;
// Output is an instance of an (dynamically generated) 'A' class, not a Func<>
return weaver.output;
}
现在有几种调用方式A.DoInt:
反射:
var c = Weaver.Weave();
var result = (int)c.GetType().GetMethod("DoInt").Invoke(c, new Object[] { 3, "foo" });
创建委托:
var c = Weaver.Weave();
var mi = c.GetType().GetMethod("DoInt");
var del = (Func<int, string, int>)Delegate.CreateDelegate(typeof(Func<int, string, int>), c, mi);
var result = del(3, "foo");
动态:
var d = Weaver.Weave() as dynamic;
var result = (int)d.DoInt(3, "foo");
接口:
这个是最难做的。首先你必须声明接口如:
public interface IDoInt
{
int DoInt(int i, string s);
}
您需要在另一个程序集中声明此接口,否则您将无法从动态定义的程序集中使用此类型(由于循环引用)。
然后你需要稍微改变一下 Weaver
,让你的 A
类型实现这个接口:
private void DefineClass()
{
this.typebuilder = this.moduleBuilder.DefineType(
"A",
TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
typeof(object),
new[] { typeof(IDoInt) });
}
private void DefineMethod()
{
MethodBuilder methodBuilder = this.typebuilder.DefineMethod(
"DoInt",
MethodAttributes.Public | MethodAttributes.HideBySig |
MethodAttributes.NewSlot | MethodAttributes.Virtual |
MethodAttributes.Final,
typeof(int), new[] { typeof(int), typeof(string) });
// ... rest ot the method is the same ...
// just add this at the end of the method to implement the IDoInt interface
this.typebuilder.DefineMethodOverride(methodBuilder, typeof(IDoInt).GetMethod("DoInt"));
}
现在可以在IDoInt
接口上调用DoInt
:
var i = Weaver.Weave() as IDoInt;
var result = i.DoInt(3, "foo");
你好,我想知道如何在不使用 reflexion.As 的情况下调用 class 的方法,你可以看到我正在使用生成器 class Weaver
(使用 Reflection.Emit
),returns a Func<object>
(我无法指定动态类型)。当我检索实例时,我将如何调用其中一个方法,特别是 DoInt
?
我想要什么AutoGenerate
class Gen {
public Gen() {
}
public int DoInt(int a,string b) {
int rez=a+b.count();
return 3;
}
}
发电机class
class Weaver {
public static Func<object> Weave() {
var weaver = new Weaver();
weaver.Run();
return weaver.output as Func<object>;
}
private AssemblyBuilder assemblyBuilder;
private ModuleBuilder moduleBuilder;
private TypeBuilder typebuilder;
private object output;
public Weaver() {
}
private void Run() {
this.DefineAssembly();
this.DefineModule();
this.DefineClass();
this.DefineMethod();
this.Wrap();
}
private void DefineAssembly() {
AssemblyName name = new AssemblyName("Coda");
AppDomain domain = AppDomain.CurrentDomain;
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
}
private void DefineModule() {
this.moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyBuilder.FullName + ".dll");
}
private void DefineClass() {
this.typebuilder = this.moduleBuilder.DefineType("A",
TypeAttributes.Abstract|TypeAttributes.Public|TypeAttributes.BeforeFieldInit|TypeAttributes.AnsiClass|TypeAttributes.AutoClass,
typeof(object), null );
}
private void DefineMethod() {
MethodBuilder methodBuilder = this.typebuilder.DefineMethod("DoInt", MethodAttributes.Public, typeof(int), new[] { typeof(int), typeof(string) });
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Call, typeof(Enumerable).GetMethod("Count", BindingFlags.Static), null);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
}
private void Wrap() {
Type type = typebuilder.CreateType();
this.output = Activator.CreateInstance(type);
}
}
主要
static void Main(string[] args)
{
string t = "astada";
var c = Weaver.Weave();
var result=c.GetType().GetMethod("DoInt").Invoke(null, new object[] { 3, "mystring" }); //should be 3+ "mystring".Count()
Console.ReadLine();
}
要使其正常工作,您首先需要修复 Weaver
,因为它包含几个错误:
private void DefineClass()
{
// TypeAttributes.Abstract should not be used here as we want to create
// type that can be instantiated
this.typebuilder = this.moduleBuilder.DefineType(
"A",
TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
typeof(object),
null);
}
private void DefineMethod()
{
MethodBuilder methodBuilder = this.typebuilder.DefineMethod(
"DoInt",
MethodAttributes.Public,
typeof(int), new[] { typeof(int), typeof(string) });
var il = methodBuilder.GetILGenerator();
// Arguments are counted from zero. For instance methods, argument0 is
// reserved for 'this' instance. So to get "string" argument (second "real" argument),
// you need Ldarg_2
il.Emit(OpCodes.Ldarg_2);
// You cannot get MethodInfo for "Count" method with simple GetMethod(),
// since it is generic method with several overloads.
var countMethodInfo = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.Name == "Count")
.Where(m => m.GetParameters().Length == 1)
.Single()
//We want Count<char>() method, because we want to count characters on string (casted to IEnumerable<char>).
.MakeGenericMethod(typeof(char));
il.EmitCall(OpCodes.Call, countMethodInfo, null);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
}
public static object Weave()
{
var weaver = new Weaver();
weaver.Run();
// return weaver.output as Func<object>;
// Output is an instance of an (dynamically generated) 'A' class, not a Func<>
return weaver.output;
}
现在有几种调用方式A.DoInt:
反射:
var c = Weaver.Weave(); var result = (int)c.GetType().GetMethod("DoInt").Invoke(c, new Object[] { 3, "foo" });
创建委托:
var c = Weaver.Weave(); var mi = c.GetType().GetMethod("DoInt"); var del = (Func<int, string, int>)Delegate.CreateDelegate(typeof(Func<int, string, int>), c, mi); var result = del(3, "foo");
动态:
var d = Weaver.Weave() as dynamic; var result = (int)d.DoInt(3, "foo");
接口:
这个是最难做的。首先你必须声明接口如:
public interface IDoInt { int DoInt(int i, string s); }
您需要在另一个程序集中声明此接口,否则您将无法从动态定义的程序集中使用此类型(由于循环引用)。
然后你需要稍微改变一下
Weaver
,让你的A
类型实现这个接口:private void DefineClass() { this.typebuilder = this.moduleBuilder.DefineType( "A", TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(object), new[] { typeof(IDoInt) }); } private void DefineMethod() { MethodBuilder methodBuilder = this.typebuilder.DefineMethod( "DoInt", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, typeof(int), new[] { typeof(int), typeof(string) }); // ... rest ot the method is the same ... // just add this at the end of the method to implement the IDoInt interface this.typebuilder.DefineMethodOverride(methodBuilder, typeof(IDoInt).GetMethod("DoInt")); }
现在可以在
IDoInt
接口上调用DoInt
:var i = Weaver.Weave() as IDoInt; var result = i.DoInt(3, "foo");