Creates a DynamicAssembly that contains a C# with Example



Creates a DynamicAssembly that contains a C# with Example

UnixTimestamp helper method 
This example shows the usage of the ILGenerator by generating code that makes use of already existing and new 
created members as well as basic Exception handling. The following code emits a DynamicAssembly that contains 
an equivalent to this c# code: 
public static class UnixTimeHelper 
{ 
private readonly static DateTime EpochTime = new DateTime(1970, 1, 1); 
public static int UnixTimestamp(DateTime input) 
{ 
int totalSeconds; 
try 
{ 
totalSeconds = checked((int)input.Subtract(UnixTimeHelper.EpochTime).TotalSeconds); 
} 
catch (OverflowException overflowException) 
{ 
throw new InvalidOperationException("It's to late for an Int32 timestamp.", 
overflowException); 
} 
return totalSeconds; 
} 
} 
//Get the required methods 
var dateTimeCtor = typeof (DateTime) 
.GetConstructor(new[] {typeof (int), typeof (int), typeof (int)}); 
var dateTimeSubstract = typeof (DateTime) 
.GetMethod(nameof(DateTime.Subtract), new[] {typeof (DateTime)}); 
var timeSpanSecondsGetter = typeof (TimeSpan) 
.GetProperty(nameof(TimeSpan.TotalSeconds)).GetGetMethod(); 
var invalidOperationCtor = typeof (InvalidOperationException) 
.GetConstructor(new[] {typeof (string), typeof (Exception)}); 
if (dateTimeCtor == null || dateTimeSubstract == null || 
timeSpanSecondsGetter == null || invalidOperationCtor == null) 
{ 
throw new Exception("Could not find a required Method, can not create Assembly."); 
} 
//Setup the required members 
var an = new AssemblyName("UnixTimeAsm"); 
var dynAsm = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave); 
var dynMod = dynAsm.DefineDynamicModule(an.Name, an.Name + ".dll"); 
var dynType = dynMod.DefineType("UnixTimeHelper", 
TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public); 
var epochTimeField = dynType.DefineField("EpochStartTime", typeof (DateTime), 
FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); 
var cctor = 
dynType.DefineConstructor( 
 

MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | 
MethodAttributes.RTSpecialName | MethodAttributes.Static, CallingConventions.Standard, 
Type.EmptyTypes); 
var cctorGen = cctor.GetILGenerator(); 
cctorGen.Emit(OpCodes.Ldc_I4, 1970); //Load the DateTime constructor arguments onto the stack 
cctorGen.Emit(OpCodes.Ldc_I4_1); 
cctorGen.Emit(OpCodes.Ldc_I4_1); 
cctorGen.Emit(OpCodes.Newobj, dateTimeCtor); //Call  the  constructor 
cctorGen.Emit(OpCodes.Stsfld, epochTimeField); //Store the object in the static field 
cctorGen.Emit(OpCodes.Ret); 
var unixTimestampMethod = dynType.DefineMethod("UnixTimestamp", 
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, 
CallingConventions.Standard, typeof (int), new[] {typeof (DateTime)}); 
unixTimestampMethod.DefineParameter(1, ParameterAttributes.None, "input"); 
var methodGen = unixTimestampMethod.GetILGenerator(); 
methodGen.DeclareLocal(typeof (TimeSpan)); 
methodGen.DeclareLocal(typeof (int)); 
methodGen.DeclareLocal(typeof (OverflowException)); 
methodGen.BeginExceptionBlock(); //Begin  the  try  block 
methodGen.Emit(OpCodes.Ldarga_S, (byte) 0); //To call a method on a struct we need to load the 
address of it 
methodGen.Emit(OpCodes.Ldsfld, epochTimeField); 
//Load the object of the static field we created as argument for the following call 
methodGen.Emit(OpCodes.Call, dateTimeSubstract); //Call the substract method on the input DateTime 
methodGen.Emit(OpCodes.Stloc_0); //Store the resulting TimeSpan in a local 
methodGen.Emit(OpCodes.Ldloca_S, (byte) 0); //Load the locals address to call a method on it 
methodGen.Emit(OpCodes.Call, timeSpanSecondsGetter); //Call the TotalSeconds Get method on the 
TimeSpan 
methodGen.Emit(OpCodes.Conv_Ovf_I4); //Convert the result to Int32; throws an exception on overflow 
methodGen.Emit(OpCodes.Stloc_1); //store the result for returning later 
//The leave instruction to jump behind the catch block will be automatically emitted 
methodGen.BeginCatchBlock(typeof (OverflowException)); //Begin the catch block 
//When we are here, an OverflowException was thrown, that is now on the stack 
methodGen.Emit(OpCodes.Stloc_2); //Store the exception in a local. 
methodGen.Emit(OpCodes.Ldstr, "It's to late for an Int32 timestamp."); 
//Load our error message onto the stack 
methodGen.Emit(OpCodes.Ldloc_2); //Load the exception again 
methodGen.Emit(OpCodes.Newobj, invalidOperationCtor); 
//Create an InvalidOperationException with our message and inner Exception 
methodGen.Emit(OpCodes.Throw); //Throw the created exception 
methodGen.EndExceptionBlock(); //End the catch block 
//When we are here, everything is fine 
methodGen.Emit(OpCodes.Ldloc_1); //Load the result value 
methodGen.Emit(OpCodes.Ret); //Return it 
dynType.CreateType(); 
dynAsm.Save(an.Name + ".dll"); 

0 Comment's

Comment Form

Submit Comment