Generieren von Quellcode und Kompilieren eines Programms aus einem CodeDOM-Diagramm

Der System.CodeDom.Compiler-Namespace stellt Schnittstellen zum Generieren von Quellcode aus CodeDOM-Objektdiagrammen und zum Verwalten der Kompilierung mit unterstützten Compilern bereit. Ein Codeanbieter kann Quellcode in einer bestimmten Programmiersprache entsprechend einem CodeDOM-Diagramm erstellen. Eine von CodeDomProvider abgeleitete Klasse kann normalerweise Methoden bereitstellen, durch die Code für die vom Anbieter unterstützte Sprache generiert und kompiliert wird.

Verwenden eines CodeDOM-Codeanbieters zum Generieren von Quellcode

Zum Generieren von Quellcode in einer bestimmten Sprache benötigen Sie ein CodeDOM-Diagramm, das die Struktur des zu generierenden Quellcodes darstellt.

Im folgenden Beispiel wird veranschaulicht, wie eine Instanz von CSharpCodeProvider erstellt wird:

Dim provider As New CSharpCodeProvider()
CSharpCodeProvider provider = new CSharpCodeProvider();
CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();

Das Diagramm für die Codegenerierung befindet sich normalerweise in einer CodeCompileUnit. Zum Generieren von Code für eine CodeCompileUnit, die ein CodeDOM-Diagramm enthält, rufen Sie die GenerateCodeFromCompileUnit-Methode des Codeanbieters auf. Diese Methode enthält einen Parameter für einen TextWriter, der zum Generieren des Quellcodes verwendet wird, sodass in einigen Fällen zunächst ein TextWriter erstellt werden muss, in den geschrieben werden kann. Das folgende Beispiel veranschaulicht das Generieren von Code aus einer CodeCompileUnit und das Schreiben des generierten Quellcodes in eine Datei mit der Bezeichnung HelloWorld.cs.

Public Shared Function GenerateCSharpCode(compileunit As CodeCompileUnit) As String
    ' Generate the code with the C# code provider.
    Dim provider As New CSharpCodeProvider()

    ' Build the output file name.
    Dim sourceFile As String
    If provider.FileExtension(0) = "." Then
       sourceFile = "HelloWorld" + provider.FileExtension
    Else
       sourceFile = "HelloWorld." + provider.FileExtension
    End If

    ' Create a TextWriter to a StreamWriter to the output file.
    Using sw As New StreamWriter(sourceFile, false)
        Dim tw As New IndentedTextWriter(sw, "    ")

        ' Generate source code Imports the code provider.
        provider.GenerateCodeFromCompileUnit(compileunit, tw, _
            New CodeGeneratorOptions())

        ' Close the output file.
        tw.Close()
    End Using

    Return sourceFile
End Function
public static string GenerateCSharpCode(CodeCompileUnit compileunit)
{
    // Generate the code with the C# code provider.
    CSharpCodeProvider provider = new CSharpCodeProvider();

    // Build the output file name.
    string sourceFile;
    if (provider.FileExtension[0] == '.')
    {
       sourceFile = "HelloWorld" + provider.FileExtension;
    }
    else
    {
       sourceFile = "HelloWorld." + provider.FileExtension;
    }

    // Create a TextWriter to a StreamWriter to the output file.
    using (StreamWriter sw = new StreamWriter(sourceFile, false))
    {
        IndentedTextWriter tw = new IndentedTextWriter(sw, "    ");

        // Generate source code using the code provider.
        provider.GenerateCodeFromCompileUnit(compileunit, tw,
            new CodeGeneratorOptions());

        // Close the output file.
        tw.Close();
    }

    return sourceFile;
}
public:
    static String^ GenerateCSharpCode(CodeCompileUnit^ compileunit)
    {
        // Generate the code with the C# code provider.
        CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();

        // Build the output file name.
        String^ sourceFile;
        if (provider->FileExtension[0] == '.')
        {
           sourceFile = "HelloWorld" + provider->FileExtension;
        }
        else
        {
           sourceFile = "HelloWorld." + provider->FileExtension;
        }

        // Create a TextWriter to a StreamWriter to the output file.
        StreamWriter^ sw = gcnew StreamWriter(sourceFile, false);
        IndentedTextWriter^ tw = gcnew IndentedTextWriter(sw, "    ");

            // Generate source code using namespace the code provider.
        provider->GenerateCodeFromCompileUnit(compileunit, tw,
            gcnew CodeGeneratorOptions());

        // Close the output file.
        tw->Close();
        sw->Close();

        return sourceFile;
    }

Verwenden eines CodeDOM-Codeanbieters zum Kompilieren von Assemblys

Aufrufen der Kompilierung

Zum Kompilieren einer Assembly mithilfe eines CodeDom-Anbieters benötigen Sie entweder in einer Sprache zu kompilierenden Quellcode, für die ein Compiler vorhanden ist, oder ein CodeDOM-Diagramm, aus dem der zu kompilierende Quellcode generiert werden kann.

Wenn Sie aus einem CodeDOM-Diagramm kompilieren, übergeben Sie die CodeCompileUnit mit dem Diagramm an die CompileAssemblyFromDom-Methode des Codeanbieters. Bei einer Quellcodedatei in einer vom Compiler unterstützten Sprache übergeben Sie der CompileAssemblyFromFile-Methode des CodeDom-Anbieters den Namen der Datei, die den Quellcode enthält. Sie können der CompileAssemblyFromSource-Methode des CodeDom-Anbieters auch eine Zeichenfolge übergeben, die den Quellcode in einer vom Compiler unterstützten Sprache enthält.

Konfigurieren von Kompilierungsparametern

Alle Standardmethoden zum Kompilierungsaufruf eines CodeDom-Anbieters enthalten einen Parameter vom Typ CompilerParameters, der die Optionen angibt, die zum Kompilieren verwendet werden.

In der OutputAssembly-Eigenschaft von CompilerParameters können Sie einen Dateinamen für die Ausgabeassembly angeben. Andernfalls wird ein Standardname für die Ausgabedatei verwendet.

Beim Initialisieren einer neuen Instanz von CompilerParameters wird die GenerateExecutable-Eigenschaft standardmäßig auf false festgelegt. Wenn Sie ein ausführbares Programm kompilieren, müssen Sie die GenerateExecutable-Eigenschaft auf true festlegen. Wenn GenerateExecutable auf false festgelegt ist, generiert der Compiler eine Klassenbibliothek.

Wenn Sie eine ausführbare Datei aus einem CodeDOM-Diagramm kompilieren, muss im Diagramm eine CodeEntryPointMethod definiert sein. Wenn mehrere Codeeinstiegspunkte vorhanden sind, muss die MainClass-Eigenschaft von CompilerParameters möglicherweise auf den Namen der Klasse festgelegt werden, die den zu verwendenden Einstiegspunkt definiert.

Um Debuginformationen in eine generierte ausführbare Datei einzufügen, legen Sie die IncludeDebugInformation-Eigenschaft auf true fest.

Wenn das Projekt Verweise auf Assemblys enthält, müssen Sie für die ReferencedAssemblies-Eigenschaft der beim Aufruf der Kompilierung verwendeten CompilerParameters die Assemblynamen als Elemente in einer StringCollection angeben.

Sie können eine Assembly kompilieren, die nicht auf den Datenträger, sondern in den Speicher geschrieben wird, indem Sie die GenerateInMemory-Eigenschaft auf true festlegen. Wenn eine Assembly im Speicher generiert wird, kann der Code aus der CompiledAssembly-Eigenschaft von CompilerResults einen Verweis auf die generierte Assembly abrufen. Wenn eine Assembly auf einen Datenträger geschrieben wird, können Sie aus der PathToAssembly-Eigenschaft von CompilerResults den Pfad zur generierten Assembly abrufen.

Um eine benutzerdefinierte Zeichenfolge für Befehlszeilenargumente anzugeben, die beim Aufrufen der Kompilierung verwendet werden soll, legen Sie die Zeichenfolge in der CompilerOptions-Eigenschaft fest.

Wenn für den Aufruf des Compilerprozesses ein Win32-Sicherheitstoken erforderlich ist, geben Sie das Token in der UserToken-Eigenschaft an.

Um mit der kompilierten Assembly eine Win32-Ressourcendatei zu verknüpfen, geben Sie den Namen der Win32-Ressourcendatei in der Win32Resource-Eigenschaft an.

Wenn Sie eine Warnstufe angeben möchten, bei der die Kompilierung unterbrochen werden soll, legen Sie die WarningLevel-Eigenschaft auf eine ganze Zahl fest, die die Warnstufe zum Unterbrechen der Kompilierung darstellt. Sie können den Compiler auch für die Unterbrechung der Kompilierung beim Auftreten von Warnungen konfigurieren, indem Sie die TreatWarningsAsErrors-Eigenschaft auf true festlegen.

Das folgende Codebeispiel veranschaulicht die Kompilierung einer Quelldatei mithilfe eines CodeDom-Anbieters, der von der CodeDomProvider-Klasse abgeleitet wurde.

Public Shared Function CompileCSharpCode(sourceFile As String, _
    exeFile As String) As Boolean
    Dim provider As New CSharpCodeProvider()

    ' Build the parameters for source compilation.
    Dim cp As New CompilerParameters()

    ' Add an assembly reference.
    cp.ReferencedAssemblies.Add( "System.dll" )

    ' Generate an executable instead of
    ' a class library.
    cp.GenerateExecutable = true

    ' Set the assembly file name to generate.
    cp.OutputAssembly = exeFile

    ' Save the assembly as a physical file.
    cp.GenerateInMemory = false

    ' Invoke compilation.
    Dim cr As CompilerResults = provider.CompileAssemblyFromFile(cp, sourceFile)

    If cr.Errors.Count > 0 Then
        ' Display compilation errors.
         Console.WriteLine("Errors building {0} into {1}", _
             sourceFile, cr.PathToAssembly)
        For Each ce As CompilerError In cr.Errors
            Console.WriteLine("  {0}", ce.ToString())
            Console.WriteLine()
        Next ce
    Else
        Console.WriteLine("Source {0} built into {1} successfully.", _
            sourceFile, cr.PathToAssembly)
    End If

    ' Return the results of compilation.
    If cr.Errors.Count > 0 Then
        Return False
    Else
        Return True
    End If
End Function
public static bool CompileCSharpCode(string sourceFile, string exeFile)
{
    CSharpCodeProvider provider = new CSharpCodeProvider();

    // Build the parameters for source compilation.
    CompilerParameters cp = new CompilerParameters();

    // Add an assembly reference.
    cp.ReferencedAssemblies.Add( "System.dll" );

    // Generate an executable instead of
    // a class library.
    cp.GenerateExecutable = true;

    // Set the assembly file name to generate.
    cp.OutputAssembly = exeFile;

    // Save the assembly as a physical file.
    cp.GenerateInMemory = false;

    // Invoke compilation.
    CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceFile);

   if (cr.Errors.Count > 0)
   {
       // Display compilation errors.
        Console.WriteLine("Errors building {0} into {1}",
            sourceFile, cr.PathToAssembly);
        foreach (CompilerError ce in cr.Errors)
        {
            Console.WriteLine("  {0}", ce.ToString());
            Console.WriteLine();
        }
    }
    else
    {
        Console.WriteLine("Source {0} built into {1} successfully.",
            sourceFile, cr.PathToAssembly);
    }

    // Return the results of compilation.
    if (cr.Errors.Count > 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
public:
    static bool CompileCSharpCode(String^ sourceFile, String^ exeFile)
    {
        CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();

        // Build the parameters for source compilation.
        CompilerParameters^ cp = gcnew CompilerParameters();

        // Add an assembly reference.
        cp->ReferencedAssemblies->Add( "System.dll" );

        // Generate an executable instead of
        // a class library.
        cp->GenerateExecutable = true;

        // Set the assembly file name to generate.
        cp->OutputAssembly = exeFile;

        // Save the assembly as a physical file.
        cp->GenerateInMemory = false;

        // Invoke compilation.
        CompilerResults^ cr = provider->CompileAssemblyFromFile(cp, sourceFile);

       if (cr->Errors->Count > 0)
       {
           // Display compilation errors.
            Console::WriteLine("Errors building {0} into {1}",
                sourceFile, cr->PathToAssembly);
            for each (CompilerError^ ce in cr->Errors)
            {
                Console::WriteLine("  {0}", ce->ToString());
                Console::WriteLine();
            }
        }
        else
        {
            Console::WriteLine("Source {0} built into {1} successfully.",
                sourceFile, cr->PathToAssembly);
        }

        // Return the results of compilation.
        if (cr->Errors->Count > 0)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

Von Beginn an unterstützte Sprachen

.NET Framework bietet Codecompiler und Codegeneratoren für folgende Sprachen: C#, Visual Basic, C++, J# und JScript. Die CodeDOM-Unterstützung kann auf andere Sprachen erweitert werden, indem sprachspezifische Code-Generatoren und Codecompiler implementiert werden.

Siehe auch

Referenz

Kurzreferenz zum CodeDOM

System.CodeDom

System.CodeDom.Compiler

Weitere Ressourcen

Generieren und Kompilieren von dynamischem Quellcode