Generating Source Code and Compiling a Program from a CodeDOM Graph

The System.CodeDom.Compiler namespace provides interfaces for generating source code from CodeDOM object graphs and for managing compilation with supported compilers. A code provider can produce source code in a particular programming language according to a CodeDOM graph. A class that derives from CodeDomProvider can typically provide methods for generating and compiling code for the language the provider supports.

Using a CodeDOM code provider to generate source code

To generate source code in a particular language, you need a CodeDOM graph that represents the structure of the source code to generate.

The following example demonstrate how to create an instance of a CSharpCodeProvider:

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

The graph for code generation is typically contained in a CodeCompileUnit. To generate code for a CodeCompileUnit that contains a CodeDOM graph, call the GenerateCodeFromCompileUnit method of the code provider. This method has a parameter for a TextWriter that it uses to generate the source code, so it is sometimes necessary to first create a TextWriter that can be written to. The following example demonstrates generating code from a CodeCompileUnit and writing the generated source code to a file named 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;
    }

Using a CodeDOM code provider to compile assemblies

Invoking compilation

To compile an assembly using a CodeDom provider, you must have either source code to compile in a language for which you have a compiler, or a CodeDOM graph that source code to compile can be generated from.

If you are compiling from a CodeDOM graph, pass the CodeCompileUnit containing the graph to the CompileAssemblyFromDom method of the code provider. If you have a source code file in a language that the compiler understands, pass the name of the file containing the source code to the CompileAssemblyFromFile method of the CodeDom provider. You can also pass a string containing source code in a language that the compiler understands to the CompileAssemblyFromSource method of the CodeDom provider.

Configuring compilation parameters

All of the standard compilation-invoking methods of a CodeDom provider have a parameter of type CompilerParameters that indicates the options to use for compilation.

You can specify a file name for the output assembly in the OutputAssembly property of the CompilerParameters. Otherwise, a default output file name will be used.

By default, a new CompilerParameters is initialized with its GenerateExecutable property set to false. If you are compiling an executable program, you must set the GenerateExecutable property to true. When the GenerateExecutable is set to false, the compiler will generate a class library.

If you are compiling an executable from a CodeDOM graph, a CodeEntryPointMethod must be defined in the graph. If there are multiple code entry points, it may be necessary to set the MainClass property of the CompilerParameters to the name of the class that defines the entry point to use.

To include debug information in a generated executable, set the IncludeDebugInformation property to true.

If your project references any assemblies, you must specify the assembly names as items in a StringCollection as the ReferencedAssemblies property of the CompilerParameters you use when invoking compilation.

You can compile an assembly that is written to memory rather than disk by setting the GenerateInMemory property to true. When an assembly is generated in memory, your code can obtain a reference to the generated assembly from the CompiledAssembly property of a CompilerResults. If an assembly is written to disk, you can obtain the path to the generated assembly from the PathToAssembly property of a CompilerResults.

To specify a custom command-line arguments string to use when invoking the compilation process, set the string in the CompilerOptions property.

If a Win32 security token is required to invoke the compiler process, specify the token in the UserToken property.

To link a Win32 resource file into the compiled assembly, specify the name of the Win32 resource file in the Win32Resource property.

To specify a warning level at which to halt compilation, set the WarningLevel property to an integer that represents the warning level at which to halt compilation. You can also configure the compiler to halt compilation if warnings are encountered by setting the TreatWarningsAsErrors property to true.

The following code example demonstrates compiling a source file using a CodeDom provider derived from the CodeDomProvider class.

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

Languages with Initial Support

The .NET Framework provides code compilers and code generators for the following languages: C#, Visual Basic, C++, J#, and JScript. CodeDOM support can be extended to other languages by implementing language-specific code generators and code compilers.

See Also

Reference

CodeDOM Quick Reference

System.CodeDom

System.CodeDom.Compiler

Other Resources

Advanced Development Technologies