2009-05-30 9 views
16

Zamierzam zadać pytanie, które może zabrzmieć dziwnie.Czy istnieje sposób na zbudowanie nowego typu podczas uruchamiania?

Czy istnieje sposób na zbudowanie nowej klasy podczas uruchamiania? Lub przynajmniej dodaj nową właściwość do istniejącej klasy.

Mam na myśli tworzenie klasy, która nie istnieje, a nie instancję istniejącej klasy. Mógłbym później użyć odbić, aby załadować i używać tej klasy.

Odpowiedz

21

Dodawanie właściwości do istniejącego typu nie jest możliwe, ale można utworzyć nowy typ w środowisku wykonawczym za pomocą narzędzia Reflection.Emit. To dość skomplikowane rzeczy i wygląda to tak:

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

Ten kod jest tylko próbką. Może zawierać błędy.

Można również generować klasy, kompilując kod źródłowy C# w środowisku wykonawczym przy użyciu System.CodeDom, ale nie wiem zbyt wiele na ten temat.

+0

Sorry m rwwilden Marked to jako odpowiedź, ponieważ ta odpowiedź została stworzona z większym wysiłkiem (myśli zarówno zu wprowadzone to samo rozwiązanie) – user88637

+0

Nie ma problemu. Zgadzam się, że jest to trochę bardziej wyszukane niż moja własna odpowiedź. –

4

Spójrz na przestrzeń nazw System.Reflection.Emit. Nigdy go nie używałem, ale klasy w tej przestrzeni nazw mogą być używane do generowania IL (język pośredni).

+0

dzięki, to jest dokładnie to, czego szukałem – user88637

3

Możesz zajrzeć do przestrzeni nazw System.CodeDom. Według jednej ze stron połączonego stamtąd:

.NET Framework zawiera mechanizm o nazwie Object Model Code Dokument (CodeDOM), która umożliwia twórcom programów, które emitują kod źródłowy do generowania kodu źródłowego w wielu językach programowania na czas pracy oparty na pojedynczym modelu reprezentującym kod do renderowania.

Nie jestem w tym ekspertem, właśnie przypomniałem sobie, że widziałem to na moim plakacie .NET Framework na mojej ścianie. :)

Edytuj: Od napisania tej odpowiedzi grałem trochę z System.CodeDom. Napisałem numer blog post, który używa pewnej podstawowej CodeDom, która może pomóc tym, którzy chcą zacząć z nią pracować.

5

To nie jest dziwne pytanie - w niektórych przypadkach może być bardzo przydatne. Na przykład użyć tej techniki do badań skuteczności niekiedy:

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(); 
} 
Powiązane problemy