.Net development - C# from C#
Last updated on June 23, 2015, 11:33 by Sebastian Mihai
This little program I wrote (I should've called it "Yo dawg, I heard you like C#") uses a few standard .Net components to achieve the following:
create a DOM representation of a .Net class containing a method
export the DOM to a C# source code file
compile the C# source code file to a .Net DLL assembly
load the .Net DLL assembly via reflection
activate the class created earlier from the loaded assembly
invoke the method created in the first step

Essentially, this C# program creates C# source code, then compiles it, loads the compiled DLL, and then invokes a method contained within. Here are the program components, all in one file for simplicity.

The Visual Studio solution can be downloaded here. It outputs a console application.


internal static CodeNamespace CreateDOM(
string namespaceName,
string className,
string methodName
) {

// the method we're creating will simply print "Hello, world!"
CodeMethodInvokeExpression expression = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"),
"WriteLine",
new CodePrimitiveExpression("Hello, world!")
);

CodeMemberMethod myNewMethod = new CodeMemberMethod();
myNewMethod.Name = "PrintHello";
myNewMethod.ReturnType = new CodeTypeReference(typeof(void));
myNewMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
myNewMethod.Statements.Add(expression);

CodeTypeDeclaration myNewClass = new CodeTypeDeclaration(className);
myNewClass.Members.Add(myNewMethod);

CodeNamespace myNewNamespace = new CodeNamespace(namespaceName);
myNewNamespace.Imports.Add(new CodeNamespaceImport("System"));
myNewNamespace.Types.Add(myNewClass);

return myNewNamespace;
}

This method programatically creates a statement (which is an invoke expression), referencing System.Console.WriteLine, passing in the string "Hello, world!".
It then puts the expression inside a new method, which it puts inside a new class, which it puts in a new namespace, which is ultimately returned. Note how the namespace references the System namespace, so that its containing types have access to the Console class.


internal static void SaveDOMToSourceFile(
CodeNamespace newNamepace,
string outputSourceFileName
) {

CodeCompileUnit compileUnit = new CodeCompileUnit();
compileUnit.Namespaces.Add(newNamepace);

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StreamWriter sourceWriter = new StreamWriter(outputSourceFileName)) {
provider.GenerateCodeFromCompileUnit(
compileUnit,
sourceWriter,
options
);
}
}

This method simply takes a CodeNamespace and outputs its contents as C# source code to a file. It works with the CodeNamespace output from the previous method.


internal static void CompileAssemblyFromSourceFile(
string sourceFileName,
string outputAssemblyFileName
) {

CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.GenerateExecutable = false;
cp.OutputAssembly = outputAssemblyFileName;

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

CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceFileName);

if (cr.Errors.Count > 0) {
throw new Exception("Couldn't compile successfully");
}
}

This method compiles a C# source code file to a .Net DLL assembly. It works with the C# source code file created by the previous method.


static void Main(string[] args) {
string namespaceName = "SM";
string className = "Hello";
string methodName = "PrintHello";

CodeNamespace myNewNamespace = CreateDOM(
namespaceName,
className,
methodName
);

SaveDOMToSourceFile(myNewNamespace, "SM.cs");
CompileAssemblyFromSourceFile("SM.cs", "SM.dll");

// now load the assembly we've just created
Assembly assembly = Assembly.Load("SM");
string fullClassName = namespaceName + "." + className;
// and use reflection to call our method
Type type = assembly.GetType(fullClassName);
MethodInfo method = type.GetMethod(methodName);
object obj = Activator.CreateInstance(type);
method.Invoke(obj, null);

Console.ReadLine();
}

The main method should be fairly simple to follow. It chains the helper methods to create SM.dll. After that, it uses reflection to load SM.dll, activate the class Hello, and then call the method PrintHello.
If you use the materials on this page, or any other page on this web site, you do so at your own risk. They are provided "as is". No warranty is provided or implied. I neither guarantee that the materials will work, nor that they will not be harmful in any way.

.Net development - C# from C#

The naming convention of the C standards is Y2K-susceptible

Missing stack trace entries in Release mode assemblies in .Net 4.0 (C#)

Public constants across assemblies and default parameter values in C#

C# lambda operator

Simple two-column, three-panel web site template

An easy to use random number generator

Puppy Linux on a computer without a hard drive (on a USB stick!)

(My) Useful settings for fresh Windows installations on new computers

How to use multiple versions of Firefox on the same computer

How indexes work

Trivialization of history through technology

Entropy in code

Basic Linux tricks

MSSQL tips for production databases

Keep your computer clean with VMware