Динамически создать универсальный тип для шаблона

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

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

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

Решение

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

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

Вы должны посмотреть на это сообщение от Ayende: 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]);

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

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

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

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

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

Другие вопросы по тегам