动态创建模板的泛型类型

时间:2021-07-22 21:39:36

I'm programming WCF using the ChannelFactory which expects a type in order to call the CreateChannel method. For example:

我正在使用ChannelFactory编写WCF,它需要一个类型来调用CreateChannel方法。例如:

IProxy proxy = ChannelFactory<IProxy>.CreateChannel(...);

In my case I'm doing routing so I don't know what type my channel factory will be using. I can parse a message header to determine the type but I hit a brick wall there because even if I have an instance of Type I can't pass that where ChannelFactory expects a generic type.

在我的情况下,我正在做路由,所以我不知道我的渠道工厂将使用什么类型。我可以解析一个消息头来确定类型,但我在那里打了一堵砖墙,因为即使我有一个Type I实例也无法传递ChannelFactory期望泛型类型的实例。

Another way of restating this problem in very simple terms would be that I'm attempting to do something like this:

用非常简单的术语重述这个问题的另一种方法是我试图做这样的事情:

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?

Is there an approach to this I can leverage within C#?

我可以在C#中使用这种方法吗?

3 个解决方案

#1


27  

What you are looking for is MakeGenericType

您正在寻找的是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);

So what you are doing is getting the type-definition of the generic "template" class, then building a specialization of the type using your runtime-driving types.

所以你要做的是获取通用“模板”类的类型定义,然后使用运行时驱动类型构建类型的特化。

#2


8  

You should look at this post from Ayende: WCF, Mocking and IoC: Oh MY!. Somewhere near the bottom is a method called GetCreationDelegate which should help. It basically does this:

你应该看一下Ayende的这篇文章:WCF,Mocking和IoC:哦,我的!靠近底部的地方是一个名为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]);

#3


4  

Here's a question: Do you really need to create a channel with the exact contract type in your specific case?

这是一个问题:您是否真的需要在特定情况下创建具有确切合同类型的渠道?

Since you're doing routing, there's a very good chance you could simply deal with the generic channel shapes. For example, if you're routing a one-way only message, then you could create a channel to send the message out like this:

由于您正在进行路由,因此很有可能只需处理通用通道形状。例如,如果您要路由单向消息,那么您可以创建一个频道来发送消息,如下所示:

ChannelFactory<IOutputChannel> factory = new ChannelFactory<IOutputChannel>(binding, endpoint);
IOutputChannel channel = factory.CreateChannel();
...
channel.SendMessage(myRawMessage);

If you needed to send to a two-way service, just use IRequestChannel instead.

如果您需要发送双向服务,请改用IRequestChannel。

If you're doing routing, it is, in general, a lot easier to just deal with generic channel shapes (with a generic catch-all service contract to the outside) and just make sure the message you're sending has all the right headers and properties.

如果您正在进行路由,通常情况下,处理通用通道形状(与外部通用的全部服务合同)更容易,并确保您发送的消息完全正确标题和属性。

#1


27  

What you are looking for is MakeGenericType

您正在寻找的是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);

So what you are doing is getting the type-definition of the generic "template" class, then building a specialization of the type using your runtime-driving types.

所以你要做的是获取通用“模板”类的类型定义,然后使用运行时驱动类型构建类型的特化。

#2


8  

You should look at this post from Ayende: WCF, Mocking and IoC: Oh MY!. Somewhere near the bottom is a method called GetCreationDelegate which should help. It basically does this:

你应该看一下Ayende的这篇文章:WCF,Mocking和IoC:哦,我的!靠近底部的地方是一个名为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]);

#3


4  

Here's a question: Do you really need to create a channel with the exact contract type in your specific case?

这是一个问题:您是否真的需要在特定情况下创建具有确切合同类型的渠道?

Since you're doing routing, there's a very good chance you could simply deal with the generic channel shapes. For example, if you're routing a one-way only message, then you could create a channel to send the message out like this:

由于您正在进行路由,因此很有可能只需处理通用通道形状。例如,如果您要路由单向消息,那么您可以创建一个频道来发送消息,如下所示:

ChannelFactory<IOutputChannel> factory = new ChannelFactory<IOutputChannel>(binding, endpoint);
IOutputChannel channel = factory.CreateChannel();
...
channel.SendMessage(myRawMessage);

If you needed to send to a two-way service, just use IRequestChannel instead.

如果您需要发送双向服务,请改用IRequestChannel。

If you're doing routing, it is, in general, a lot easier to just deal with generic channel shapes (with a generic catch-all service contract to the outside) and just make sure the message you're sending has all the right headers and properties.

如果您正在进行路由,通常情况下,处理通用通道形状(与外部通用的全部服务合同)更容易,并确保您发送的消息完全正确标题和属性。