Есть ли способ создать новый тип во время выполнения? - PullRequest
19 голосов
/ 30 мая 2009

Я собираюсь задать вопрос, который может показаться странным.

Есть ли способ построить новый класс во время выполнения? Или, по крайней мере, добавьте новое свойство в существующий класс.

Я имею в виду создание класса, который не существует, а не экземпляр существующего класса. Позже я мог бы использовать отражения, чтобы загрузить и использовать этот класс.

Ответы [ 4 ]

24 голосов
/ 30 мая 2009

Добавление свойства к существующему типу невозможно, но вы можете создать новый тип во время выполнения, используя 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();

Этот код является просто примером. Может содержать ошибки.

Вы также можете генерировать классы, компилируя исходный код C # во время выполнения, используя System.CodeDom, но я об этом немного знаю.

5 голосов
/ 30 мая 2009

Это не странный вопрос - в некоторых случаях это может быть очень полезно. Например, я иногда использую эту технику для тестов производительности:

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();
}
5 голосов
/ 30 мая 2009

Взгляните на пространство имен System.Reflection.Emit . Я никогда не использовал его сам, но классы в этом пространстве имен можно использовать для генерации IL (промежуточный язык).

3 голосов
/ 30 мая 2009

Вы можете взглянуть на пространство имен System.CodeDom . По одной из страниц, на которые есть ссылки:

.NET Framework включает механизм, называемый объектной моделью документа кода (CodeDOM), который позволяет разработчикам программ, генерирующих исходный код, генерировать исходный код на нескольких языках программирования во время выполнения на основе единой модели, представляющей код для визуализации.

Я вовсе не эксперт в этом, я только что вспомнил, что видел это на своем плакате .NET Framework на моей стене. :)

Редактировать: С момента написания этого ответа я немного поиграл с System.CodeDom. Я написал сообщение в блоге , в котором используется базовый CodeDom, который может помочь тем, кто хочет начать работу с ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...