C# 有没有办法在运行时构建新类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/929349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:26:14  来源:igfitidea点击:

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

c#.netvb.netreflection

提问by user88637

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.

有没有办法在运行时构建一个新类?或者至少,向现有类添加一个新属性。

I mean creating a class that doesn't exist and not an instance of an existing class. I could later on use reflections to load and use this class.

我的意思是创建一个不存在的类而不是现有类的实例。我稍后可以使用反射来加载和使用这个类。

采纳答案by Philippe Leybaert

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:

向现有类型添加属性是不可能的,但您可以在运行时使用 Reflection.Emit 创建一个新类型。这是非常复杂的东西,它是这样的:

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.

您还可以通过在运行时使用 System.CodeDom 编译 C# 源代码来生成类,但我对此知之甚少。

回答by Ronald Wildenberg

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

查看System.Reflection.Emit命名空间。我自己从未使用过它,但此命名空间中的类可用于生成 IL(中间语言)。

回答by Daniel Chambers

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

您可以查看System.CodeDom命名空间。根据从那里链接的页面之一:

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.

.NET Framework 包括一种称为代码文档对象模型 (CodeDOM) 的机制,它使发出源代码的程序的开发人员能够在运行时基于表示要呈现的代码的单个模型生成多种编程语言的源代码。

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

我根本不是这方面的专家,我只是记得在我墙上的 .NET Framework 海报上看到过它。:)

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

编辑:自从写了这个答案,我玩了一点 System.CodeDom。我写了一篇博客文章,其中使用了一些基本的 CodeDom,可以帮助那些想要开始使用它的人。

回答by tanascius

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();
}