Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#TypeBuilder使用函数动态生成类_C#_Function_Class_Dynamic_Typebuilder - Fatal编程技术网

C#TypeBuilder使用函数动态生成类

C#TypeBuilder使用函数动态生成类,c#,function,class,dynamic,typebuilder,C#,Function,Class,Dynamic,Typebuilder,我试图在C#中使用TypeBuilder动态生成一个带有函数的类,并让该函数调用另一个基函数 之所以需要这样做,是因为在Revit应用程序开发中,每个按钮都需要有一个类,该类通过执行函数实现IExternalCommand。我希望动态创建按钮,并根据它们的ID在运行时处理它们的执行,因此我也需要动态创建类 希望这段代码能够理解我要查找的内容(或此处): 我试着让一个TypeBuilder运行起来,我知道了基本原理,但我似乎不知道如何使用操作码来获得我喜欢的类 因此,基本上我在寻找编写genera

我试图在C#中使用TypeBuilder动态生成一个带有函数的类,并让该函数调用另一个基函数

之所以需要这样做,是因为在Revit应用程序开发中,每个按钮都需要有一个类,该类通过执行函数实现IExternalCommand。我希望动态创建按钮,并根据它们的ID在运行时处理它们的执行,因此我也需要动态创建类

希望这段代码能够理解我要查找的内容(或此处):

我试着让一个TypeBuilder运行起来,我知道了基本原理,但我似乎不知道如何使用操作码来获得我喜欢的类

因此,基本上我在寻找编写generateClass(intid)函数的帮助。任何帮助都将不胜感激

编辑:

这段代码更接近,但是当运行它时,我得到了错误

System.TypeLoadException:类型“GeneratedClass99”中的方法“Execute” 从程序集的DynamicAssemblyExample,Version=0.0.0.0, Culture=neutral,PublicKeyToken=null'没有实现


当我在
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 { }
    // =================================================================== //
}