Подтвердить что ты не робот

Есть ли способ создать новый тип во время выполнения?

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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

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