繁体   English   中英

将类名传递给泛型类型

[英]Pass class name to generic type

标题可能有点误导,但我不确定如何恰当地用词,因此,如果有人知道更好的标题,请进行编辑。

我有一个方法,该方法采用必须从MessageBaseReadMessage )派生的泛型类型。 现在,我有了一个都从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...
}

使用ActionFunc可以为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM