Is there a way to build a new type during Runtime?

前端 未结 4 1084
[愿得一人]
[愿得一人] 2020-12-28 15:47

I am going to ask a question that might sound weird.

Is there a way to build a new class during Runtime? Or at least, add a new property to an existing class.

<
相关标签:
4条回答
  • 2020-12-28 16:16

    This is not a weird question - in some cases it might be very useful. For instance I use this technique for performance tests sometimes:

    public static Type[] DynamicTypes;
    
    public void CreateObjects()
    {
      var codeNamespace = new CodeNamespace( "DynamicClasses" );
      codeNamespace.Imports.Add( new CodeNamespaceImport( "System" ) );
      codeNamespace.Imports.Add( new CodeNamespaceImport( "System.ComponentModel" ) );
    
      for( var i = 0; i < 2000; i++ )
      {
        var classToCreate = new CodeTypeDeclaration( "DynamicClass_" + i )
        {
          TypeAttributes = TypeAttributes.Public
        };
        var codeConstructor1 = new CodeConstructor
        {
          Attributes = MemberAttributes.Public
        };
        classToCreate.Members.Add( codeConstructor1 );
    
        codeNamespace.Types.Add( classToCreate );
      }
    
      var codeCompileUnit = new CodeCompileUnit();
      codeCompileUnit.Namespaces.Add( codeNamespace );
    
      var compilerParameters = new CompilerParameters
      {
        GenerateInMemory = true,
        IncludeDebugInformation = true,
        TreatWarningsAsErrors = true,
        WarningLevel = 4
      };
      compilerParameters.ReferencedAssemblies.Add( "System.dll" );
    
      var compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom( compilerParameters, codeCompileUnit );
    
      if( compilerResults == null )
      {
        throw new InvalidOperationException( "ClassCompiler did not return results." );
      }
      if( compilerResults.Errors.HasErrors )
      {
        var errors = string.Empty;
        foreach( CompilerError compilerError in compilerResults.Errors )
        {
          errors += compilerError.ErrorText + "\n";
        }
        Debug.Fail( errors );
        throw new InvalidOperationException( "Errors while compiling the dynamic classes:\n" + errors );
      }
    
      var dynamicAssembly = compilerResults.CompiledAssembly;
      DynamicTypes = dynamicAssembly.GetExportedTypes();
    }
    
    0 讨论(0)
  • 2020-12-28 16:17

    You might take a look at the System.CodeDom namespace. According to one of the pages linked from there:

    The .NET Framework includes a mechanism called the Code Document Object Model (CodeDOM) that enables developers of programs that emit source code to generate source code in multiple programming languages at run time, based on a single model that represents the code to render.

    I'm not at all an expert in this, I just remembered seeing it on my .NET Framework poster on my wall. :)

    Edit: Since writing this answer, I have played with System.CodeDom a bit. I've written a blog post that uses some basic CodeDom that may help those wanting to get started with it.

    0 讨论(0)
  • 2020-12-28 16:26

    Adding a property to an existing type is not possible, but you can create a new type at runtime using Reflection.Emit. It's pretty complicated stuff, and it goes something like this:

    AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
          assemblyName , AssemblyBuilderAccess.Run, assemblyAttributes);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
    TypeBuilder typeBuilder = moduleBuilder.DefineType(
          "MyNamespace.TypeName" , TypeAttributes.Public);
    
    typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
    
    // Add a method
    newMethod = typeBuilder.DefineMethod("MethodName" , MethodAttributes.Public);
    
    ILGenerator ilGen = newMethod.GetILGenerator();
    
    // Create IL code for the method
    ilGen.Emit(...);
    
    // ...
    
    // Create the type itself
    Type newType = typeBuilder.CreateType();
    

    This code is just a sample. It could contain errors.

    You can also generate classes by compiling C# source code at runtime using System.CodeDom, but I don't know a lot about that.

    0 讨论(0)
  • 2020-12-28 16:32

    Take a look at the System.Reflection.Emit namespace. I've never used it myself but the classes in this namespace can be used to generate IL (intermediate language).

    0 讨论(0)
提交回复
热议问题