Existe-t-il un moyen de créer un nouveau type pendant l’exécution?

Je vais poser une question qui peut paraître étrange.

Existe-t-il un moyen de créer une nouvelle classe pendant l’exécution? Ou du moins, ajoutez une nouvelle propriété à une classe existante.

Je veux dire créer une classe qui n’existe pas et non une instance d’une classe existante. Je pourrais plus tard utiliser des reflections pour charger et utiliser cette classe.

L’ajout d’une propriété à un type existant n’est pas possible, mais vous pouvez créer un nouveau type à l’exécution à l’aide de Reflection.Emit. C’est assez compliqué, et ça ressemble à ça:

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

Ce code est juste un exemple. Il pourrait contenir des erreurs.

Vous pouvez également générer des classes en compilant le code source C # à l’exécution à l’aide de System.CodeDom, mais je ne connais pas grand chose à ce sujet.

Ce n’est pas une question étrange – dans certains cas, cela pourrait être très utile. Par exemple, j’utilise cette technique pour des tests de performance parfois:

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

Jetez un coup d’œil à l’espace de noms System.Reflection.Emit . Je ne l’ai jamais utilisé moi-même, mais les classes de cet espace de noms peuvent être utilisées pour générer du langage intermédiaire (IL).

Vous pouvez jeter un oeil à l’espace de noms System.CodeDom . Selon l’une des pages liées à partir de là:

Le .NET Framework comprend un mécanisme appelé CodeDOM (Code Document Object Model) qui permet aux développeurs de programmes émettant du code source de générer du code source dans plusieurs langages de programmation au moment de l’exécution, en se basant sur un modèle unique représentant le code à restituer.

Je ne suis pas du tout un expert en la matière, je viens juste de me souvenir de l’avoir vue sur mon affiche .NET Framework sur mon mur. 🙂

Edit: Depuis que j’ai écrit cette réponse, j’ai un peu joué avec System.CodeDom. J’ai écrit un article de blog qui utilise un code de base qui peut aider ceux qui veulent en commencer.