C#TypeBuilder使用函数动态生成类
我试图在C#中使用TypeBuilder动态生成一个带有函数的类,并让该函数调用另一个基函数 之所以需要这样做,是因为在Revit应用程序开发中,每个按钮都需要有一个类,该类通过执行函数实现IExternalCommand。我希望动态创建按钮,并根据它们的ID在运行时处理它们的执行,因此我也需要动态创建类 希望这段代码能够理解我要查找的内容(或此处): 我试着让一个TypeBuilder运行起来,我知道了基本原理,但我似乎不知道如何使用操作码来获得我喜欢的类 因此,基本上我在寻找编写generateClass(intid)函数的帮助。任何帮助都将不胜感激 编辑: 这段代码更接近,但是当运行它时,我得到了错误 System.TypeLoadException:类型“GeneratedClass99”中的方法“Execute” 从程序集的DynamicAssemblyExample,Version=0.0.0.0, Culture=neutral,PublicKeyToken=null'没有实现C#TypeBuilder使用函数动态生成类,c#,function,class,dynamic,typebuilder,C#,Function,Class,Dynamic,Typebuilder,我试图在C#中使用TypeBuilder动态生成一个带有函数的类,并让该函数调用另一个基函数 之所以需要这样做,是因为在Revit应用程序开发中,每个按钮都需要有一个类,该类通过执行函数实现IExternalCommand。我希望动态创建按钮,并根据它们的ID在运行时处理它们的执行,因此我也需要动态创建类 希望这段代码能够理解我要查找的内容(或此处): 我试着让一个TypeBuilder运行起来,我知道了基本原理,但我似乎不知道如何使用操作码来获得我喜欢的类 因此,基本上我在寻找编写genera
当我在
generateClass
(..)中调用CreateType
(..)时,会发生此错误。首先,您必须修复正在使用的参数类型。请注意,message
参数具有ref
属性,因此您应该将typeof(String)
更改为Type.GetType(“System.String&”)
在您必须声明execute方法从接口实现(重写)execute方法之后:
tb.DefineMethodOverride(mbExecute, typeof(IExternalCommand).GetMethod("Execute"));
我使用控制台应用程序进行了一些测试,通过上面的更改,我能够使其正常工作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
int a;
string s = "";
while ((a = int.Parse(Console.ReadLine())) != 0)
{
var t = DynamicButton.generateClass(a);
((IExternalCommand)t.GetConstructor(new Type[0]).Invoke(new object[0])).Execute(null, ref s, null);
}
}
}
public interface IExternalCommand
{
Result Execute(ExternalCommandData revit, ref string message, ElementSet elements);
}
public class DynamicButton
{
// I would like to use a function like this to generate the class during runtime, presumably using TypeBuilder:
public static Type generateClass(int id)
{
// ... Code which would generate a class with the name "GeneratedClass" with the 'id' parameter appended at the end
// ... The class implements IExternalCommand
// ... The class has an Execute function with the parameters listed in the example, which returns a call to the Execute function in DynamicButton
// along with the added integer 'id' parameter at the end
AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);
// For a single-module assembly, the module name is usually
// the assembly name plus an extension.
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// Create class which extends Object and implements IExternalCommand
var implements = new Type[] {typeof(IExternalCommand)};
TypeBuilder tb = mb.DefineType("GeneratedClass" + id, TypeAttributes.Public, typeof(Object), implements);
// Create 'Execute' function sig
Type[] paramList = {typeof(ExternalCommandData), Type.GetType("System.String&"), typeof(ElementSet)};
MethodBuilder mbExecute = tb.DefineMethod("Execute", MethodAttributes.Public | MethodAttributes.Virtual, typeof(Result), paramList);
// Create 'Execute' function body
ILGenerator ilGen = mbExecute.GetILGenerator();
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldarg_1);
ilGen.Emit(OpCodes.Ldarg_2);
ilGen.Emit(OpCodes.Ldarg_3);
ilGen.Emit(OpCodes.Ldc_I4_S, id);
Type[] paramListWID = { typeof(ExternalCommandData), Type.GetType("System.String&"), typeof(ElementSet), typeof(int) };
ilGen.EmitCall(OpCodes.Call, typeof(DynamicButton).GetMethod("Execute"), paramListWID);
ilGen.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mbExecute, typeof(IExternalCommand).GetMethod("Execute"));
return tb.CreateType();
}
public static Result Execute(ExternalCommandData revit, ref string message, ElementSet elements, int id)
{
Console.WriteLine("About {0}", "ID of the class that called us: " + id);
return Result.Succeeded;
}
}
public enum Result
{
Succeeded
}
public class ExternalCommandData { }
public class ElementSet { }
// =================================================================== //
}
tb.DefineMethodOverride(mbExecute, typeof(IExternalCommand).GetMethod("Execute"));
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
int a;
string s = "";
while ((a = int.Parse(Console.ReadLine())) != 0)
{
var t = DynamicButton.generateClass(a);
((IExternalCommand)t.GetConstructor(new Type[0]).Invoke(new object[0])).Execute(null, ref s, null);
}
}
}
public interface IExternalCommand
{
Result Execute(ExternalCommandData revit, ref string message, ElementSet elements);
}
public class DynamicButton
{
// I would like to use a function like this to generate the class during runtime, presumably using TypeBuilder:
public static Type generateClass(int id)
{
// ... Code which would generate a class with the name "GeneratedClass" with the 'id' parameter appended at the end
// ... The class implements IExternalCommand
// ... The class has an Execute function with the parameters listed in the example, which returns a call to the Execute function in DynamicButton
// along with the added integer 'id' parameter at the end
AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);
// For a single-module assembly, the module name is usually
// the assembly name plus an extension.
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// Create class which extends Object and implements IExternalCommand
var implements = new Type[] {typeof(IExternalCommand)};
TypeBuilder tb = mb.DefineType("GeneratedClass" + id, TypeAttributes.Public, typeof(Object), implements);
// Create 'Execute' function sig
Type[] paramList = {typeof(ExternalCommandData), Type.GetType("System.String&"), typeof(ElementSet)};
MethodBuilder mbExecute = tb.DefineMethod("Execute", MethodAttributes.Public | MethodAttributes.Virtual, typeof(Result), paramList);
// Create 'Execute' function body
ILGenerator ilGen = mbExecute.GetILGenerator();
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldarg_1);
ilGen.Emit(OpCodes.Ldarg_2);
ilGen.Emit(OpCodes.Ldarg_3);
ilGen.Emit(OpCodes.Ldc_I4_S, id);
Type[] paramListWID = { typeof(ExternalCommandData), Type.GetType("System.String&"), typeof(ElementSet), typeof(int) };
ilGen.EmitCall(OpCodes.Call, typeof(DynamicButton).GetMethod("Execute"), paramListWID);
ilGen.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mbExecute, typeof(IExternalCommand).GetMethod("Execute"));
return tb.CreateType();
}
public static Result Execute(ExternalCommandData revit, ref string message, ElementSet elements, int id)
{
Console.WriteLine("About {0}", "ID of the class that called us: " + id);
return Result.Succeeded;
}
}
public enum Result
{
Succeeded
}
public class ExternalCommandData { }
public class ElementSet { }
// =================================================================== //
}