C’è un modo per creare un nuovo tipo durante il runtime?

Sto per fare una domanda che potrebbe sembrare strana.

C’è un modo per build una nuova class durante il runtime? O almeno, aggiungi una nuova proprietà a una class esistente.

Intendo creare una class che non esiste e non un’istanza di una class esistente. Potrei in seguito utilizzare le riflessioni per caricare e utilizzare questa class.

L’aggiunta di una proprietà a un tipo esistente non è ansible, ma è ansible creare un nuovo tipo in fase di esecuzione utilizzando Reflection.Emit. È roba abbastanza complicata, e va qualcosa del genere:

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

Questo codice è solo un esempio. Potrebbe contenere errori.

Puoi anche generare classi compilando il codice sorgente C # in fase di runtime usando System.CodeDom, ma non ne so molto.

Questa non è una domanda strana – in alcuni casi potrebbe essere molto utile. Ad esempio, uso questa tecnica per i test delle prestazioni a volte:

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

Dai uno sguardo allo spazio dei nomi System.Reflection.Emit . Non l’ho mai usato da solo, ma le classi in questo spazio dei nomi possono essere utilizzate per generare IL (linguaggio intermedio).

Si potrebbe dare un’occhiata allo spazio dei nomi System.CodeDom . Secondo una delle pagine collegate da lì:

.NET Framework include un meccanismo denominato Code Document Object Model (CodeDOM) che consente agli sviluppatori di programmi che emettono codice sorgente di generare codice sorgente in più linguaggi di programmazione in fase di esecuzione, in base a un singolo modello che rappresenta il codice da rappresentare.

Non sono affatto un esperto in questo, mi sono appena ricordato di averlo visto sul mio poster di .NET Framework sulla mia bacheca. 🙂

Modifica: Da quando ho scritto questa risposta, ho giocato un po ‘con System.CodeDom. Ho scritto un post sul blog che utilizza alcuni CodeDom di base che possono aiutare coloro che vogliono iniziare con esso.