Rick Livesey said:
Hi Daniel,
Yep, I want to call into MSIL code that I had previously generated.
I thought this would be possible.
So it it just as simple as adding an assembly reference to my existing
c# solution, then calling into the pre-compiled functions?
Or I suppose if I didn't know which pre-compiled assemblies were
avaialble, I'd just have to late bind to them and have a common
interface?
Ta
r
What follows is a simple example from:
Programming C#, Third Edition
by Jesse Liberty
http://www.amazon.com/exec/obidos/asin/0596004893
http://www.oreilly.com/catalog/progcsharp3/
Chapter 18: Attributes and Reflection
p.534
Look for "public class ReflectionTest"
//-----[BEGIN]----
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace Programming_CSharp {
public class TestDriver {
public static void Main(string[] args) {
const int val = 2000; // 1..2000
// 1,000,000 iterations
const int iterations = 1000000;
int result = 0;
// run the Benchmark
MyMath m = new MyMath();
DateTime startTime = DateTime.Now;
for( int i = 0; i < iterations; ++i )
result = m.DoSumLooping( val );
TimeSpan elapsed = DateTime.Now - startTime;
Console.WriteLine( "Sum of ({0}) = {1}", val,
result );
Console.WriteLine( "Looping. Elapsed
milliseconds is: "
+ elapsed.TotalMilliseconds.ToString()
+ " for {0} iterations" , iterations
);
ReflectionTest t = new ReflectionTest();
startTime = DateTime.Now;
for( int i = 0; i < iterations; ++i )
result = t.DoSum(val);
elapsed = DateTime.Now - startTime;
Console.WriteLine( "Loop: Sum of ({0}) = {1}",
val, result );
Console.WriteLine( "Looping. Elapsed
milliseconds is: "
+ elapsed.TotalMilliseconds.ToString()
+ " for {0} iterations" , iterations
);
} // end method Main
}
public class MyMath{
// sum numbers with a loop
public int DoSumLooping(int initialVal) {
int result = 0;
for( int i = 1; i <= initialVal; ++i )
result += i;
return result;
} // end method DoSum
} // end class MyMath
public interface IComputer {
int ComputeSum();
}
// responsible for creating the BruteForceSums
// class and compiling it and invoking the
// DoSums method dynamically
public class ReflectionTest {
IComputer theComputer = null;
// the private method which emits the assembly
// using op codes
private Assembly EmitAssembly(int theValue ){
// Create an assembly name
AssemblyName assemblyName =
new AssemblyName();
assemblyName.Name = "DoSumAssembly";
// Create a new assembly with one module
AssemblyBuilder newAssembly =
Thread.GetDomain().DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run
);
ModuleBuilder newModule =
newAssembly.DefineDynamicModule("Sum");
// Define a public class named "BruteForceSums"
// in the assembly
TypeBuilder myType =
newModule.DefineType(
"BruteForceSums",
TypeAttributes.Public
);
// Mark the class as implementing IComputer
myType.AddInterfaceImplementation(
typeof(IComputer)
);
// Define a method on the type of call. Pass an
// array the defines the types of the parameters
// the type of the return type, the name of the
// method, and the method attributes.
Type[] paramTypes = new Type[0];
Type returnType = typeof(int);
MethodBuilder simpleMethod =
myType.DefineMethod(
"ComputeSum",
MethodAttributes.Public |
MethodAttributes.Virtual,
returnType,
paramTypes
);
// Get an ILGenerator. This is used
// to emit the IL that you want.
ILGenerator generator =
simpleMethod.GetILGenerator();
// Emit the IL that you'd get if you
// compiled the code example
// and then run ILDasm on the output.
// Push zero onto the stack. For each 'i'
// less than 'theValue',
// push 'i' onto the stack as a constant
// add the two values at the top of the stack.
// The sum is left on the stack
generator.Emit( OpCodes.Ldc_I4, 0 );
for( int i = 1; i <= theValue; ++i ){
generator.Emit( OpCodes.Ldc_I4, i );
generator.Emit( OpCodes.Add );
}
// return the value
generator.Emit( OpCodes.Ret );
// Encapsulate information about the method and
// provide access to the method's metadata
MethodInfo computeSumInfo =
typeof( IComputer ).GetMethod("ComputeSum");
// Specify the method implementation
// Pass in the MethodBuilder that was returned
// by calling DefineMethod and the methodInfo
// just created.
myType.DefineMethodOverride( simpleMethod,
computeSumInfo );
// Create the type.
myType.CreateType();
return newAssembly;
} // end method EmitAssembly
// the public method called by the driver
public int DoSum(int theValue){
// if you don't have a reference
// to the dynamically created class
// create it
if( theComputer == null ){
GenerateCode(theValue);
}
return (theComputer.ComputeSum());
} // end method DoSum
private void GenerateCode(int theValue ){
Assembly theAssembly = EmitAssembly( theValue );
theComputer =
(IComputer)theAssembly.CreateInstance("BruteForceSums");
} // end method GenerateCode
} // end class ReflectionTest
}
//-----[END]----