簡體   English   中英

處理創建大量子類型對象的最佳方法

[英]Best way to handle creation of large number of subtype objects

我有一個基本的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個委托方法的大型類。 那是遙遠的第二選擇。 另一個想法也是我的第一選擇,就是讓上述代碼以某種方式創建消息子類對象。 但是,我不太了解它將如何做到這一點。 同樣,將上述技術保留在我的Test類中來獲取所有類型或委托,而不必編寫所有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();
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM