处理创建大量子类型对象的最佳方式

本文关键字:对象 最佳 方式 类型 创建 处理 | 更新日期: 2023-09-27 17:57:55

我有一个基本Message类,以及大约100个不同的Message子类型类,它们表示可以处理的每种类型的消息。我目前正在考虑使用一个巨大的switch语句来创建消息对象。例如:

switch (MsgType)
{
   case MessageType.ChatMsg:
      Msg = new MsgChat(Buf);
      break;
   case MessageType.ResultMsg:
      Msg = new MsgResult(Buf);
      break;
   ... // 98 more case statements
}
Msg.ProcessMsg(); // Use a polymorphic call to process the message.

有更好的方法吗?如果是的话,你能展示一个简单的代码示例吗。

编辑

所以,我试着这样做:

public class Test
{
   public Test()
   {
      IEnumerable<Type> myEnumerable = GetTypesWith<MyAttribute>(true);
   }
   IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit)
      where TAttribute : System.Attribute
   {
      return from a in AppDomain.CurrentDomain.GetAssemblies()
             from t in a.GetTypes()
             where t.IsDefined(typeof(TAttribute), inherit)
             select t;
   }
}

这似乎是因为myEnumerable现在包含了所有100个消息子类型,以及基本消息类型。然而,虽然我不介意在程序开始时使用反射来加载类型,但使用它来实时访问正确的对象可能太慢了。因此,我想尝试使用委托。

下面评论中的例子来自@Mark Hildreth:

"所以,你会有一个>的字典。然后,你的映射将是mappings[MessageType.ChatMsg]=x=>new MsgChat(x);"

有几种方法可以解释此代码。一个想法是删除所有100个子类,只使用一个带有100个委托方法的大型类。这是一个遥远的第二选择。另一个想法也是我的第一个选择是,上面的代码以某种方式创建一个消息子类对象。但是,我不太明白它是怎么做到的。此外,如果能在我的测试课上保留上述技巧,即获得所有类型或委托,而不必编写所有100个类型或委托。你或其他人能解释一下如何做到这一点吗?

处理创建大量子类型对象的最佳方式

您可以定义一个Dictionary,将每个MessageType值映射到其定义的Message派生类,并使用此映射数据创建一个实例,而不是使用一个巨大的switch语句。

字典定义:

Dictionary<int, Type> mappings = new Dictionary<int, Type>();
mappings.Add(MessageType.ChatMsg, typeof(MsgChat));
mappings.Add(MessageType.ResultMsg, typeof(MsgResult));

字典消耗:

ConstructorInfo ctor = mappings[MessageType.ChatMsg].GetConstructor(new[] { typeof(Buf) });
Message message = (Message)ctor.Invoke(new object[] { Buf });

请注意,我编译此代码不是为了验证是否正确。我只想告诉你这个想法。

编辑

这是我改进第一个答案的新答案。我正在思考您编辑后的问题,使用@MikeSW@Mark Hildreth给出的想法。

public class FactoryMethodDelegateAttribute : Attribute
{
    public FactoryMethodDelegateAttribute(Type type, string factoryMethodField, Message.MessageType typeId)
    {
        this.TypeId = typeId;
        var field = type.GetField(factoryMethodField);
        if (field != null)
        {
            this.FactoryMethod = (Func<byte[], Message>)field.GetValue(null);
        }
    }
    public Func<byte[], Message> FactoryMethod { get; private set; }
    public Message.MessageType TypeId { get; private set; }
}
public class Message
{
    public enum MessageType
    {
        ChatMsg,
    }
}
[FactoryMethodDelegate(typeof(ChatMsg), "FactoryMethodDelegate", Message.MessageType.ChatMsg)]
public class ChatMsg : Message
{
    public static readonly MessageType MessageTypeId = MessageType.ChatMsg;
    public static readonly Func<byte[], Message> FactoryMethodDelegate = buffer => new ChatMsg(buffer);
    public ChatMsg(byte[] buffer)
    {
        this.Buffer = buffer;
    }
    private byte[] Buffer { get; set; }
 }
public class TestClass
{
    private IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) where TAttribute : Attribute
    {
        return from a in AppDomain.CurrentDomain.GetAssemblies()
               from t in a.GetTypes()
               where t.IsDefined(typeof(TAttribute), inherit)
               select t;
    }
    [Test]
    public void Test()
    {
        var buffer = new byte[1];
        var mappings = new Dictionary<Message.MessageType, Func<byte[], Message>>();
        IEnumerable<Type> types = this.GetTypesWith<FactoryMethodDelegateAttribute>(true);
        foreach (var type in types)
        {
            var attribute =
                (FactoryMethodDelegateAttribute)
                type.GetCustomAttributes(typeof(FactoryMethodDelegateAttribute), true).First();
            mappings.Add(attribute.TypeId, attribute.FactoryMethod);
        }
        var message = mappings[Message.MessageType.ChatMsg](buffer);
    }
}

您正走在正确的道路上,使用字典是个好主意。如果反射太慢,可以使用表达式,如下所示(我假设您使用MessageTypeAttribute来装饰Messages类)。

public class Test
{
 public Test()
  {
     var dict=new Dictionary<MessageType,Func<Buffer,Mesage>>();
     var types=from a in AppDomain.CurrentDomain.GetAssemblies()
         from t in a.GetTypes()
         where t.IsDefined(MessageTypeAttribute, inherit)
         select t;
    foreach(var t in types) {
      var attr = t.GetCustomAttributes(typeof (MessageTypeAttribute), false).First();
       dict[attr.MessageType] = CreateFactory(t);
       }
      var msg=dict[MessageType.Chat](Buf);
  }
 Func<Buffer,Message> CreateFactory(Type t)
 {
      var arg = Expression.Parameter(typeof (Buffer));
        var newMsg = Expression.New(t.GetConstructor(new[] {typeof (Buffer)}),arg);
        return Expression.Lambda<Func<Buffer, Message>>(newMsg, arg).Compile();
}
}