将类名传递给泛型类型

时间:2017-01-30 19:59:28

标签: c# generics unity3d

标题可能有点误导,但我不确定如何恰当地说出来,所以如果有人知道更好的标题,请编辑。

我有一个方法,它采用必须从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,以便我知道哪个字符串是正确的。

另外,这是ReadMessagepublic TMsg ReadMessage<TMsg> () where TMsg : MessageBase, new();

的签名

澄清:

我在一个函数中发送一堆我想要聚合的不同网络消息并从该方法分发。为此,我需要使ReadMessage函数动态化以适应不同的MessageBase类型。

4 个答案:

答案 0 :(得分:1)

如果字典的唯一目的是根据指定的整数值调用适当的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#中的泛型(我们仍然是相对简单和高效的代码)。在这种情况下,您不需要反思。

否则,如果你想要反思,你可以参考蒂姆的回答。

或者,您可以使用依赖注入框架。

最佳解决方案取决于您的实际代码以及将来可能需要的内容。最好在public virtual ReadMessage类中使用MessageBase方法,并仅将字典用于创建目的。这样,您就会尊重SRP原则并使代码更易于维护和扩展。

答案 1 :(得分:0)

是否符合你想要的东西?

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 {
}

这将找到当前程序集中名为&#34; MyMessageBase01&#34;的第一个类。并使用它来构造ReadMessage();

的方法

要在制作中使用,您希望比查找该名称的第一种类型更加明智,并且您希望将字符串存储到字典中的类型查找,这样您就不必反映每种类型每次都在集会中。

答案 2 :(得分:0)

您可以使用System.Reflection中的Type.GetType(string)

请查看此link了解详情。

答案 3 :(得分:0)

@Tim的回答指出了我正确的方向,即:How do I use reflection to call a generic method?C#:System.Reflection.MethodInfo cause : (Object does not match target type)

解决问题的代码段:

// 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);