代码之家  ›  专栏  ›  技术社区  ›  Stuart

以编程方式创建类似的类,包括方法

  •  0
  • Stuart  · 技术社区  · 9 年前

    希望是标题,解释了我的问题,但我试图做的是以编程方式创建类,但每个类都有不同的属性以及特定于每个类的方法。

    目前,每个类都是手动创建的,但如果可能,我希望将其更改为编程方式。目前,每个类的外观如下:

    public class SomeEventName : EventBase
    {
    
        public string HardwareId { get; set; }
        public ushort ComponantStatus { get; set; }
    
        public override string ToString()
        {
            return string.Format("SomeEventName event - HardwareId: {0}, GeneratedTime: {1}, ReceivedTime: {2}", HardwareId , GeneratedTime, ReceivedTime);
        }
    
        public static SomeEventName Default(string tvmId, DateTime createTime, DateTime receiveTime)
        {
            return new SomeEventName 
            {
                HardwareId = hardwareId,
                GeneratedTime = generatedTime,
                ReceivedTime = receivedTime,
                AdaptedTime = DateTime.UtcNow
            };
        }
    }
    

    我有替换的名字,但本质上

    • SomeEventName 将是事件的名称
    • 属性将特定于该事件
    • 这个 ToString 覆盖将需要替换 某些事件名称 对于类的实际类型
    • 这个 Default 方法将需要返回类的实例。

    我知道类可以通过使用 Reflection.Emit ,但说到方法,我只看到了一些方法 IL 我想避免的代码。我可以改变 目标字符串 重写以使用参数打印类类型,但我不确定如何处理 违约 方法

    必须具备的条件是,我显然需要能够实例化所述类,并且我需要以下代码行来返回实际类型,而不是某些泛型名称:

    typeof(SomeEventName);
    

    因此 Reflection 我的最佳选择,如果是,有没有办法处理 违约 方法而不必使用 国际劳工组织 密码或者我可以用另一种方式来解决这个问题吗?

    3 回复  |  直到 9 年前
        1
  •  0
  •   Waescher    9 年前

    假设您想用给定的类编写程序集,可以使用 runsharp 。一旦掌握了语法,就可以在运行时编写程序集,您可以从其他应用程序中引用。

    声明非常直接,您可以使用它编写有效的.NET程序集(带有可反射的.NET代码),而不必处理IL。

        2
  •  0
  •   elchido    9 年前

    如果您使用的是C#6,则可以使用Roslyn服务来动态编译C#。例如,请参见 here .

        3
  •  0
  •   Community Neeleshkumar S    7 年前

    因此,我有一种方法可以通过使用泛型实现我所需要的,并从答案中获得帮助- Dynamically create a class in C#

    第一件事是转换 SomeEventName 使用泛型,这样我就可以将其用作基类。这个 GetType() 这样我就可以区分可以创建的每种类型。这给了我:

    public class EventBase
    {
        public string HardwareId { get;set; }
        public DateTime MessageGeneratedTime { get; set; }
        public DateTime MessageReceivedTime { get; set; }
        public DateTime MessageAdaptedTime { get; set; }
    
        public override string ToString()
        {
            return string.Format("{0} event - HardwareId: {1}, CreateTime: {2}, MessageReceivedTime: {3}", GetType(), HardwareId, MessageGeneratedTime, MessageReceivedTime);
        }
    
        public T Default<T>(string dardwareId, DateTime createTime, DateTime receiveTime) where T : TestBase, new()
        {
            var instance = new T
            {
                HardwareId = hardwareId,
                MessageGeneratedTime = createTime,
                MessageReceivedTime = receiveTime,
                MessageAdaptedTime = DateTime.UtcNow
            };
    
            return instance;
        }
    }
    

    接下来我需要实例化每个类型。我一开始只有一种类型,但我可以很容易地扩展我所拥有的内容来创建其他类型。因此,在上述答案的帮助下,我最终得出:

    var myType = CompileResultType(properties);
    var myObject = Activator.CreateInstance(myType);
    

    虽然我不会包括答案中的所有代码,但关键是:

    private static TypeBuilder GetTypeBuilder()
    {
        var typeSignature = "SomeEventName";
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("TypeOfTest");
        TypeBuilder tb = moduleBuilder.DefineType(typeSignature
            , TypeAttributes.Public |
            TypeAttributes.Class |
            TypeAttributes.AutoClass |
            TypeAttributes.AnsiClass |
            TypeAttributes.BeforeFieldInit |
            TypeAttributes.AutoLayout, 
            typeof(TestBase),
            null);
    
        return tb;
    }
    

    在该代码中,我创建了 某些事件名称 给它我的基类, EventBase .

    曾经我有一次 type object ,然后我可以传递一些参数并调用 Default 方法,同时使其成为泛型。

    var arguements = new object[] { "QWERTY", DateTime.UtcNow, DateTime.UtcNow };
    
    var @event = myObject.GetType().GetMethod("Default").MakeGenericMethod(myObject.GetType()).Invoke(myObject, arguements);
    

    因为这是在控制台应用程序中,所以我可以调用 ToString override,基于上述代码中的参数,输出:

    SomeEventName事件-设备:QWERTY,创建时间:05/10/2015 15:18:25, 消息接收时间:2015年10月5日15:18:25

    另一个要求是我可以创建属性,在上面的代码中,您可以看到我调用 CompileResultType 传递参数列表。所以我所做的就是:

    var properties = new Dictionary<string, string>();
    
    properties.Add("Field1", "System.String");
    properties.Add("Field2", "System.Int32");
    

    然后,我当然可以通过以下方式设置它们的值:

    myObject.GetType().GetProperty("Field1").SetValue(myObject, "Hello world");
    myObject.GetType().GetProperty("Field2").SetValue(myObject, 987);
    

    然后使用以下命令将它们输出到控制台窗口:

    Console.WriteLine("Field1: {0}", myObject.GetType().GetProperty("Field1").GetValue(myObject));
    Console.WriteLine("Field2: {0}", myObject.GetType().GetProperty("Field2").GetValue(myObject));
    

    虽然它可能不是最好的解决方案,而且它确实有它的缺点,比如一切都变成了字符串,但它做了所需的事情。如上所述,这仅适用于一种类型,但可以通过传递 signature 作为字符串 编译结果类型 然后将其传递给 GetTypeBuilder .