动态创建一个通用类型的模板

17
我正在使用ChannelFactory编写WCF程序,该工具需要指定一个类型才能调用CreateChannel方法。例如:
IProxy proxy = ChannelFactory<IProxy>.CreateChannel(...);

在我的情况下,我正在进行路由,因此我不知道我的通道工厂将使用哪种类型。我可以解析消息头以确定类型,但我遇到了一个难题,即使我有Type的实例,我也无法将其传递给ChannelFactory期望的泛型类型。
换句话说,我试图做的事情是类似于这样:
string listtype = Console.ReadLine(); // say "System.Int32"
Type t = Type.GetType( listtype);
List<t> myIntegers = new List<>(); // does not compile, expects a "type"
List<typeof(t)> myIntegers = new List<typeof(t)>(); // interesting - type must resolve at compile time?

有没有在C#中可以利用的方法来解决这个问题?


3个回答

37

您要查找的是 MakeGenericType。

string elementTypeName = Console.ReadLine();
Type elementType = Type.GetType(elementTypeName);
Type[] types = new Type[] { elementType };

Type listType = typeof(List<>);
Type genericType = listType.MakeGenericType(types);
IProxy  proxy = (IProxy)Activator.CreateInstance(genericType);

所以您正在做的是获取通用 "模板" 类的类型定义,然后使用您的运行时驱动类型构建该类型的特化。


1
我们实际上可以直接调用 listType.MakeGenericType(elementType) - 它是 params 参数。 - rsenna

8
你应该查看Ayende的这篇文章:WCF, Mocking and IoC: Oh MY!。在底部附近有一个名为GetCreationDelegate的方法,应该会有所帮助。它基本上做了这个:
string typeName = ...;
Type proxyType = Type.GetType(typeName);

Type type = typeof (ChannelFactory<>).MakeGenericType(proxyType);

object target = Activator.CreateInstance(type);

MethodInfo methodInfo = type.GetMethod("CreateChannel", new Type[] {});

return methodInfo.Invoke(target, new object[0]);

4
这里有一个问题:在你的具体情况下,您是否真的需要创建与确切合同类型相对应的通道?
由于您正在进行路由,因此很有可能您可以简单地处理通用通道形状。例如,如果您正在路由仅单向消息,则可以创建一个通道以像这样发送消息:
ChannelFactory<IOutputChannel> factory = new ChannelFactory<IOutputChannel>(binding, endpoint);
IOutputChannel channel = factory.CreateChannel();
...
channel.SendMessage(myRawMessage);

如果你需要发送到双向服务,只需使用IRequestChannel。

如果你正在进行路由,在一般情况下,最好只处理通用的通道形状(具有通用的服务契约),并确保你发送的消息具有所有正确的标头和属性。


1
我在标记我的问题的“答案”时遇到了一个困境。在使用WCF方面,我能够使用您提到的技术,它非常有效(谢谢!)。尽管有更好的方法,但我选择了上述方法,因为它从技术上回答了我所提出的问题。 - t3rse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接