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