当前位置: 首页 > 编程笔记 >

C#创建一个包含UnixTimestamp帮助程序方法的DynamicAssembly

邓仲卿
2023-03-14
本文向大家介绍C#创建一个包含UnixTimestamp帮助程序方法的DynamicAssembly,包括了C#创建一个包含UnixTimestamp帮助程序方法的DynamicAssembly的使用技巧和注意事项,需要的朋友参考一下

示例

本示例通过生成使用现有成员和新创建成员以及基本异常处理的代码,展示了ILGenerator的用法。以下代码发出一个DynamicAssembly,其中包含与此c#代码等效的内容:

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;
    }
}

//获取所需的方法
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.");
}

//设置所需的成员
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); //将DateTime构造函数参数加载到堆栈上
cctorGen.Emit(OpCodes.Ldc_I4_1);
cctorGen.Emit(OpCodes.Ldc_I4_1);
cctorGen.Emit(OpCodes.Newobj, dateTimeCtor); //调用构造函数
cctorGen.Emit(OpCodes.Stsfld, epochTimeField); //将对象存储在静态字段中   
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(); //开始尝试块
methodGen.Emit(OpCodes.Ldarga_S, (byte) 0); //要在结构上调用方法,我们需要加载它的地址
methodGen.Emit(OpCodes.Ldsfld, epochTimeField);
    //加载我们作为以下调用的参数创建的静态字段的对象
methodGen.Emit(OpCodes.Call, dateTimeSubstract); //在输入的DateTime上调用substract方法
methodGen.Emit(OpCodes.Stloc_0); //将生成的TimeSpan存储在本地
methodGen.Emit(OpCodes.Ldloca_S, (byte) 0); //加载本地地址以在其上调用方法
methodGen.Emit(OpCodes.Call, timeSpanSecondsGetter); //在TimeSpan上调用TotalSeconds Get方法
methodGen.Emit(OpCodes.Conv_Ovf_I4); //将结果转换为Int32; 在溢出时引发异常
methodGen.Emit(OpCodes.Stloc_1); //存储结果供以后返回
//跳转到catch块后面的请假指令将自动发出
methodGen.BeginCatchBlock(typeof (OverflowException)); //开始捕获块
//当我们在这里时,抛出了OverflowException,它现在已经在堆栈中
methodGen.Emit(OpCodes.Stloc_2); //将异常存储在本地。
methodGen.Emit(OpCodes.Ldstr, "It's to late for an Int32 timestamp.");
    //将我们的错误消息加载到堆栈上
methodGen.Emit(OpCodes.Ldloc_2); //再次加载异常
methodGen.Emit(OpCodes.Newobj, invalidOperationCtor);
    //使用我们的消息和内部Exception创建一个InvalidOperationException
methodGen.Emit(OpCodes.Throw); //抛出创建的异常
methodGen.EndExceptionBlock(); //结束挡块
//当我们在这里,一切都很好
methodGen.Emit(OpCodes.Ldloc_1); //加载结果值
methodGen.Emit(OpCodes.Ret); //把它返还

dynType.CreateType();

dynAsm.Save(an.Name + ".dll");
           

 类似资料:
  • 本文向大家介绍C#程序创建一个简单线程,包括了C#程序创建一个简单线程的使用技巧和注意事项,需要的朋友参考一下 为了创建线程,我创建了一个函数- 调用上述函数以创建线程,并创建一个新的ThreadStart委托- 示例 使用以下代码创建一个简单的线程。 输出结果

  • 有人知道怎么做吗?如有任何帮助,不胜感激 问候,

  • 问题内容: 我需要创建一个Spring bean,使其门店,,一个HttpServletRequest的对象的属性,这样,因为我需要我可以注入这个bean到其他豆类。 在我看来,这些属性不会随任何URI更改,因此最好将其初始化一次(无论如何,多次传递实例根本不那么昂贵)。 问题是,如何将实例注入配置Bean?我更喜欢基于xml的注入。最可能的是,我们需要注入它作为一个,但我不知道会是什么或者这个对

  • 问题内容: java中有没有一种方法可以用指定数量的指定字符创建字符串?就我而言,我需要创建一个包含10个空格的字符串。我当前的代码是: 有没有更好的方法来完成同一件事。特别是我想快速(在执行方面)。 问题答案: for循环将由编译器优化。在像您这样的情况下,您无需自己担心优化。信任编译器。 顺便说一句,如果有一种方法可以创建一个包含n个空格字符的字符串,那么它的编码方式就和您刚才一样。

  • A package is a directory with some code and a package.json file that provides information to Yarn about your package. Most packages use some kind of version control system. The most common one is git

  • 问题内容: 我正在尝试打开文件并创建一个列表,其中每行都从文件中读取。 但是由于这样说,这个示例代码给了我一个错误。我这是什么问题 我如何编写代码以增加InFile中每个新行的列表数? 问题答案: 比这容易得多: 这将返回文件中每一行的列表。