Microsoft KB Archive/821778

= HOW TO: Create An Assembly at Runtime and Call Methods =

PSS ID Number: 821778

Article Last Modified on 8/8/2003

-

The information in this article applies to:


 * Microsoft Visual C# .NET (2003)
 * Microsoft Visual C# .NET (2002)

-



IN THIS TASK

 * SUMMARY
 * Requirements
 * Generate the Assembly Runtime and Call the Method from the Generated Assembly
 * Complete Source Code
 * Generated C# Code
 * REFERENCES



SUMMARY
This step-by-step article describes how to generate and compile Microsoft Visual C# code at runtime and how to call the methods from the newly created assembly.

Microsoft .NET Framework provides a very useful namespace that is named CodeDOM (from code document object model) to automatically generate source code for various languages. The .NET Framework also provides the Microsoft.CSharp namespace. The Microsoft.CSharp namespace provides C# language-specific code provider.

back to the top

Requirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that are required:
 * Microsoft Visual Studio .NET

This article assumes that you are familiar with the following topics:
 * Microsoft Visual Studio .NET
 * Reflection
 * Document Object Model (DOM)

back to the top

Generate the Assembly Runtime and Call the Method from the Generated Assembly
 Create a new Console Application in Visual C# .NET. By default, Class1 is created. Rename Class1.cs as CodeGen.cs .  Paste the following code at the beginning of the CodeGen.cs file. The using directive allows the names in a namespace to be used without the namespace-name as an explicit qualifier. using System.CodeDom; using System.CodeDom.Compiler; using System.Reflection; using System.IO; using Microsoft.CSharp;   Create a file that has a .cs extension by using the Stream class object: Stream codeFile = File.Open(&quot;c:\\mysample.cs&quot;, FileMode.Create);   Create a StreamWriter class to write a character stream to the local hard disk (C drive): StreamWriter sw = new StreamWriter(codeFile);   To generate code in C# programmatically, use the CSharpCodeProvider class.  CSharpCodeProvider provides access to instances of the C# code generator and to the code compiler.</li> The ICodeGenerator interface is used to generate code in a particular language dynamically.</li> To create the code in C#, call the CreateGenerator method of CSharpCodeProvider, and then assign this to the object of ICodeGenerator.</li> CodeGeneratorOptions class is used to set configuration properties for structuring the code. The properties set by the CodeGeneratorOptions object are used by Code Generator to generate the code. In this sample, properties are not set.</li></ul>

CSharpCodeProvider cscp = new CSharpCodeProvider; ICodeGenerator codeGenerator = cscp.CreateGenerator(sw); CodeGeneratorOptions cgo = new CodeGeneratorOptions; </li>  To generate a namespace declaration statement, use the CodeSnippetCompileUnit class. This class represents a literal code fragment that can be compiled. To generate the code from the compile unit, call the GenerateCodeFromCompileUnit method of ICodeGenerator. CodeSnippetCompileUnit cscu = new CodeSnippetCompileUnit(&quot;using System&quot;); codeGenerator.GenerateCodeFromCompileUnit(cscu, sw, cop); </li>  To generate a namespace for the assembly, use the CodeNamespace class. All the generated code is enclosed in this namespace. CodeNamespace cnsCodeDom = new CodeNamespace(&quot;mynamespace&quot;); </li>  Create a Sample class. This class has one method, ShowHello, and displays a &quot;Hello World&quot; string. To create this class, create an instance of the CodeTypeDeclaration class, and then set the required properties of the instance, as shown in following code: CodeTypeDeclaration clsDecl = new CodeTypeDeclaration; clsDecl.Name = &quot;Sample&quot;; clsDec.IsClass = true; clsDecl.TypeAttributes = TypeAttributes.Public; cnsCodeNamespace.Types.Add(clsDecl); </li>  Create a default class constructor, as shown in the following code: CodeConstructor clsConstructor = new CodeConstructor; clsConstructor.Attributes = MemberAttributes.Public; clsDecl.Members.Add(CodeConstructor); </li>  Create a public ShowHello method for the Sample class. ShowHello displays a &quot;Hello World&quot; string. CodeMemberMethod clsMethod = new CodeMemberMethod; clsMethod.Name = &quot;ShowHello&quot;; clsMethod.ReturnType = new CodeTypeReference(&quot;void&quot;); clsMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; clsMethod.Statements.Add(new CodeSnippetStatement(&quot;Console.WriteLine(\&quot;Hello World\&quot;);&quot;); clsDecl.Members.Add(clsMethod); </li>  Use the following code to call the GenerateCodeFromNamespace method. This method will generate the C# source code from the cnsCodeDom namespace to the stream writer object, sw. cscg.GenerateCodeFromNamespace(cnsCodeDom, sw, cop); </li>  Close both the StreamWriter object and the Stream object.  sw.Close; codeFile.Close; </li>  To compile and generate the assembly, create an instance of C# compiler and set the compiler options. After you set the C# compiler options, compile the MySample.cs file. The CompileAssemblyFromFile method of ICodeCompiler compiles an assembly from the source code that is contained in the specified file by using the specified compiler settings.Check the return value of the CompileAssemblyFromFile method. CompilerParameters compparams = new CompilerParameters; compparams.GenerateExecutable = false; compparams.OutputAssembly=&quot;c:\\mySample.dll&quot;; compparams.ReferencedAssemblies.Add(&quot;System.dll&quot;);

ICodeCompiler cscompiler = cscp.CreateCompiler; CompilerResults compresult = cscompiler.CompileAssemblyFromFile(compparams,&quot;c:\\mysample.cs&quot;); if ( compresult == null || compresult.Errors.Count > 0 ) {   for( int i=0; i<compresult.Output.Count; i++ ) Console.WriteLine( compresult.Output[i] ); for( int i=0; i<compresult.Errors.Count; i++ ) Console.WriteLine( i.ToString + &quot;: &quot; + compresult.Errors[i].ToString );

} </li>  Create an instance of the Sample class. If the previous step compiles the assembly correctly by using the compresult object, you can create an instance of the Sample class. object instance = compresult.CompiledAssembly.CreateInstance(&quot;mynamespace.Sample&quot;); </li>  Obtain the ShowHello method from the newly created instance of the Sample class. Type clsType = compresult.CompiledAssembly.GetType(&quot;mynamespace.Sample&quot;); MethodInfo methodinf = clsType.GetMethod(&quot;ShowHello&quot;); </li>  Call the ShowHello method. Because ShowHello does not take any parameters, pass null as the second parameter to call the method. methodinf.Invoke(instance, null); </li></ol>

back to the top

Complete Code Listing
using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Reflection; using System.IO; using Microsoft.CSharp;

namespace SampleCodeGen {   class CodeGen {       [STAThread] static void Main(string[] args) {           Stream codeFile = File.Open(&quot;c:\\mysample.cs&quot;, FileMode.Create); StreamWriter sw = new StreamWriter(codeFile);

CSharpCodeProvider cscp = new CSharpCodeProvider; ICodeGenerator codeGenerator = cscp.CreateGenerator(sw); CodeGeneratorOptions cgo = new CodeGeneratorOptions;

CodeSnippetCompileUnit cscu = new CodeSnippetCompileUnit(&quot;using System;&quot;); codeGenerator.GenerateCodeFromCompileUnit(cscu, sw, cgo);

CodeNamespace cnsCodeNamespace = new CodeNamespace(&quot;mynamespace&quot;);

CodeTypeDeclaration clsDecl = new CodeTypeDeclaration; clsDecl.Name = &quot;Sample&quot;; clsDecl.IsClass = true; clsDecl.TypeAttributes = TypeAttributes.Public;

cnsCodeNamespace.Types.Add(clsDecl);

CodeConstructor clsConstructor = new CodeConstructor; clsConstructor.Attributes = MemberAttributes.Public; clsDecl.Members.Add(clsConstructor); CodeMemberMethod clsMethod = new CodeMemberMethod; clsMethod.Name = &quot;ShowHello&quot;; clsMethod.ReturnType = new CodeTypeReference (&quot;System.Void&quot;); clsMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; clsMethod.Statements.Add(new CodeSnippetStatement(@&quot;Console.WriteLine(&quot;&quot;Hello World!&quot;&quot;);&quot;)); clsDecl.Members.Add(clsMethod);

codeGenerator.GenerateCodeFromNamespace(cnsCodeNamespace,sw,cgo);

sw.Close; codeFile.Close;

CompilerParameters compparams = new CompilerParameters; compparams.GenerateExecutable = false; compparams.OutputAssembly=&quot;c:\\mySample.dll&quot;; compparams.ReferencedAssemblies.Add(&quot;System.dll&quot;);

ICodeCompiler cscompiler = cscp.CreateCompiler; CompilerResults compresult = cscompiler.CompileAssemblyFromFile(compparams,&quot;c:\\mysample.cs&quot;); if ( compresult == null || compresult.Errors.Count > 0 ) {               for( int i=0; i<compresult.Output.Count; i++ ) Console.WriteLine( compresult.Output[i] ); for( int i=0; i<compresult.Errors.Count; i++ ) Console.WriteLine( i.ToString + &quot;: &quot; + compresult.Errors[i].ToString );

}

object instance = compresult.CompiledAssembly.CreateInstance(&quot;mynamespace.Sample&quot;); Type clsType = compresult.CompiledAssembly.GetType(&quot;mynamespace.Sample&quot;); MethodInfo methodinf = clsType.GetMethod(&quot;ShowHello&quot;); methodinf.Invoke(instance, null);

}   } } back to the top

Generated C# Code
using System; namespace mynamespace { public class Sample { public Sample { }       public void ShowHello { Console.WriteLine(&quot;Hello World!&quot;); }   } } back to the top

<div class="references_section">