Generieren und Kompilieren von Quellcode aus einem CodeDOM-Diagramm

Der System.CodeDom.Compiler-Namespace stellt Schnittstellen zum Generieren von Sourcecode aus CodeDOM-Objektdiagrammen und zum Verwalten der Kompilierung mit unterstützten Compilern bereit. Ein Codeanbieter kann Quellcode in einer bestimmten Programmiersprache anhand eines CodeDOM-Diagramms erstellen. Eine Klasse, die von CodeDomProvider abgeleitet wurde, kann in der Regel Methoden zum Generieren und Kompilieren von Code für die Sprache bereitstellen, die der Anbieter unterstützt.

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 Quellcode darstellt.

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

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

Das Diagramm für die Generierung von Code ist in der Regel Bestandteil 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 verfügt einen Parameter für eine TextWriter, die zum Generieren des Quellcodes verwendet wird. Deshalb ist es manchmal erforderlich, zuerst eine TextWriter-Klasse zu erstellen, in die geschrieben werden kann. Das folgende Beispiel veranschaulicht die Erstellung von Code aus einer CodeCompileUnit und das Schreiben des generierten Quellcodes in eine Datei mit der Bezeichnung „HelloWorld.cs“.

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

Verwenden eines CodeDOM-Codeanbieters zum Kompilieren von Assemblys

Aufrufen der Kompilierung

Um eine Assembly mit einem CodeDom-Anbieter zu kompilieren, müssen Sie entweder Quellcode besitzen, um in eine Sprache zu kompilieren, für die Sie einen Compiler oder ein CodeDOM-Diagramm besitzen, von 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. Wenn Sie über eine Quellcodedatei in einer Sprache verfügen, die der Compiler versteht, übergeben Sie den Namen der Datei, die den Quellcode enthält, an die CompileAssemblyFromFile-Methode des CodeDom-Anbieters. Sie können auch eine Zeichenfolge an die CompileAssemblyFromSource-Methode des CodeDom-Anbieters übergeben, die den Quellcode in einer Sprache enthält, die der Compiler versteht.

Konfigurieren von Kompilierungsparametern

Alle Standardmethoden zum Kompilierungsaufruf eines CodeDom-Anbieters besitzen einen Parameter vom Typ CompilerParameters, der die erforderlichen Optionen für die Kompilierung anzeigt.

Sie können den Dateinamen für die Ausgabeassembly in der OutputAssembly-Eigenschaft der CompilerParameters angeben. Andererseits wird ein Standardname für die Ausgabedatei verwendet.

Standardmäßig wird ein neues CompilerParameters initialisiert, wobei seine Eigenschaft GenerateExecutable auf false festgelegt wird. 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 eine CodeEntryPointMethod im Diagramm definiert werden. Wenn es mehrere Codeeinstiegspunkte gibt, kann es womöglich erforderlich sein, die MainClass-Eigenschaft von CompilerParameters auf den Namen der Klasse festzulegen, die den zu verwendenden Einstiegspunkt definiert.

Um die Debuginformation in eine generierte ausführbare Datei einzuschließen, legen Sie die IncludeDebugInformation-Eigenschaft auf true fest.

Wenn Ihr Projekt auf Assemblys verweist, müssen Sie die Assemblynamen als Elemente in einer StringCollection als ReferencedAssemblies-Eigenschaft von CompilerParameters angeben, die Sie beim Aufruf der Kompilierung verwenden.

Sie können eine Assembly kompilieren, die zum Speicher und nicht auf den Datenträger geschrieben wurde, indem Sie die GenerateInMemory-Eigenschaft auf true festlegen. Wenn eine Assembly im Speicher generiert wird, kann Ihr Code einen Verweis aus einer CompiledAssembly-Eigenschaft einer CompilerResults für die generierte Assembly abrufen. Wenn eine Assembly auf den Datenträger geschrieben wird, können Sie den Pfad zur generierten Assembly aus der PathToAssembly-Eigenschaft einer CompilerResults abrufen.

Um einen benutzerdefinierte Argumentzeichenfolge auf Befehlszeilenebene anzugeben, die Sie beim Aufruf des Kompilierungsprozesses verwenden, legen Sie die Zeichenfolge in der CompilerOptions-Eigenschaft fest.

Wenn ein Win32-Sicherheitstoken erforderlich ist, um den Compilerprozess auszurufen, geben Sie das Token in der UserToken-Eigenschaft an.

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

Wenn Sie eine Warnstufe angeben möchten, an der Sie die Kompilierung anhalten möchten, legen Sie die WarningLevel-Eigenschaft auf einen Integer fest, der die Warnstufe darstellt, an der die Kompilierung angehalten werden soll. Sie können auch den Compiler konfigurieren, um die Kompilierung anzuhalten, wenn Warnungen aufgetreten sind, indem Sie die TreatWarningsAsErrors-Eigenschaft auf true festlegen.

Das folgende Codebeispiel stellt die Kompilierung einer Quelldatei mithilfe des CodeDom-Anbieters dar, der aus der CodeDomProvider-Klasse abgeleitet wurde.

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

Sprachen mit erweiterter Unterstützung

.NET bietet Codecompiler für Codegeneratoren für die folgenden Sprachen: C#, Visual Basic, C++ und JScript. Die CodeDOM-Unterstützung kann auf andere Sprachen durch Implementierung sprachspezifischer Codegeneratoren und Codecompiler erweitert werden.

Siehe auch