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");