我有一个基本的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:
“所以,你有一个&gt;字典。然后,你的映射将是映射[MessageType.ChatMsg] = x =&gt; new MsgChat(x);”
有几种方法可以解释此代码。一个想法是删除所有100个子类,只使用一个100个委托方法的大型类。这是一个遥远的第二选择。另一个想法和我的第一个选择是上面的代码以某种方式创建一个消息子类对象。但是,我不太明白它会如何做到这一点。另外,在我的Test类中保持上述技术获取所有类型或委托而不必编写所有100个这样的技术会很好。您或其他任何人可以解释如何做到这一点吗?
答案 0 :(得分:3)
使用巨型switch
语句,您可以定义Dictionary
以将每个MessageType
值映射到其定义的Message
派生类,并使用此映射数据创建实例
字典定义:
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);
}
}
答案 1 :(得分:2)
你走在正确的轨道上,使用字典是一个好主意。如果反射太慢,你可以使用像这样的表达式(我假设你使用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();
}
}