[英]Pass class name to generic type
标题可能有点误导,但我不确定如何恰当地用词,因此,如果有人知道更好的标题,请进行编辑。
我有一个方法,该方法采用必须从MessageBase
( ReadMessage )派生的泛型类型。 现在,我有了一个都从MessageBase继承的类名列表,如下所示:
public Dictionary<int,string> messageBaseNames = new Dictionary<int,string>();
可以说我的字典看起来像这样:
messageBaseNames = {
{ 1 : "MyMessageBase01" },
{ 2 : "MyMessageBase02" },
{ 3 : "AnotherMessageBase" }
}
ReadMessage
方法通常如下使用:
public void ProcessMessageBase(NetworkMessage netMsg) {
var msg = netMsg.ReadMessage<MyMessageBase01>();
}
是否可以将这些字符串类表示形式传递给ReadMessage
泛型类型? netMsg
的值很short
因此我知道哪个字符串是正确的。
另外,这是ReadMessage
的签名: public TMsg ReadMessage<TMsg> () where TMsg : MessageBase, new();
为了澄清:
我要发送一堆不同的网络消息,这些消息要聚合到一个函数中并从该方法分发。 为此,我需要使该ReadMessage
函数动态化以适应不同的MessageBase类型。
如果字典的唯一目的是根据指定的整数值调用适当的ReadMessage
方法,那么我将改用函数字典。
public dictionary<int, Func<NetworkMessage, MessageBase>> messageBaseReaders;
然后我用
messageBaseReaders.Add(1, (nm) => nm.ReadMessage<MyMessageBase01>());
messageBaseReaders.Add(2, (nm) => nm.ReadMessage<MyMessageBase02>());
messageBaseReaders.Add(3, (nm) => nm.ReadMessage<AnotherMessageBase>());
然后我会像这样使用它们:
Func<NetworkMessage, MessageBase> reader;
if (messageBaseReaders.TryGetValue(msgId, out reader))
{
var msg = reader(netMsg);
}
else
{
// Desired error handling...
}
使用Action
和Func
可以为C#中的泛型提供更大的灵活性(尽管我们还是相对简单高效的代码)。 在这种情况下,您将不需要反思。
否则,如果您想反思,可以参考蒂姆的答案。
或者,您可以使用依赖项注入框架。
最佳解决方案取决于您的实际代码以及将来可能需要的代码。 最好在MessageBase
类中有一个public virtual ReadMessage
方法,并仅将字典用于创建目的。 这样,您将尊重SRP原则,并使代码更具可维护性和可扩展性。
是否可以满足您的需求?
class Program {
static void Main(string[] args) {
var method = typeof(SomeClass).GetMethod("ReadMessage");
var readMessage = method.MakeGenericMethod(System.Reflection.Assembly.GetExecutingAssembly().GetTypes().First(p => p.Name == "MyMessageBase01"));
var o = new SomeClass();
Console.WriteLine(readMessage.Invoke(o, null));
}
}
public class SomeClass {
public string ReadMessage<T>() {
return typeof(T).FullName;
}
}
public class MyMessageBase01 {
}
这将在当前程序集中找到名为“ MyMessageBase01”的第一个类,并将其用于构造ReadMessage()的方法。
要在生产环境中使用,您不仅要查找该名称的第一种类型,还希望更加明智,并且您希望将字符串存储在字典中以进行类型查找,因此您不必每次都在程序集中反映每种类型。
您可以使用System.Reflection
Type.GetType(string)
。
查看此链接以获取更多信息。
@Tim的答案为我指明了正确的方向,即: 如何使用反射调用泛型方法? 和C#:System.Reflection.MethodInfo原因:(对象与目标类型不匹配) 。
解决该问题的代码段:
// Type.EmptyTypes is very crucial, because there are two methods with
// the same `ReadMessage` name. The one that doesn't take parameters
// was the needed one.
MethodInfo method = typeof(NetworkMessage).GetMethod ("ReadMessage",Type.EmptyTypes,null);
MethodInfo generic = method.MakeGenericMethod (*messageBaseTypes*);
// In the referred thread `this` was passed instead of `netMsg`
// However, an instance of the object is needed, else
// a `TargetException : Object does not match target type` is thrown.
var msg = generic.Invoke (netMsg, null);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.