Динамически Создать общий шаблон для шаблона

Я программирую WCF с помощью ChannelFactory, который ожидает тип, чтобы вызвать метод CreateChannel. Например:

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

В моем случае я делаю маршрутизацию, поэтому не знаю, какой тип будет использовать мой канал factory. Я могу разобрать заголовок сообщения, чтобы определить тип, но я ударил по кирпичной стене, потому что, даже если у меня есть экземпляр типа I, я не могу передать это, когда 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?

Есть ли подход к этому, я могу использовать в С#?

Ответ 1

То, что вы ищете, это 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);

Итак, что вы делаете, это получение типа-определения общего шаблона "шаблон", а затем построение специализации типа с использованием типов во время выполнения.

Ответ 2

Вы должны посмотреть этот пост от Айенде: WCF, Mocking и 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]);

Ответ 3

Вот вопрос: нужно ли вам действительно создать канал с точным типом контракта в вашем конкретном случае?

Поскольку вы выполняете маршрутизацию, есть очень хороший шанс, что вы можете просто иметь дело с общими формами каналов. Например, если вы маршрутизируете одностороннее сообщение, вы можете создать канал для отправки сообщения следующим образом:

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

Если вам нужно отправить двустороннюю службу, просто используйте IRequestChannel.

Если вы выполняете маршрутизацию, проще всего просто иметь дело с родовыми формами каналов (с общим контрактом на доступ к всем остальным услугам) и просто убедитесь, что отправляемое сообщение все правильные заголовки и свойства.