Создание дженериков со многими типами

#c# #generics

#c# #обобщения

Вопрос:

У меня есть фрагмент кода, где иногда мне нужно создать новый универсальный тип, но с неизвестным количеством универсальных параметров. Например:

 public object MakeGenericAction(Type[] types)
{
  return typeof(Action<>).MakeGenericType(paramTypes);
}
  

Проблема в том, что если у меня в массиве более одного типа, то программа завершится сбоем. В краткосрочной перспективе я придумал что-то вроде этого в качестве промежуточного звена.

 public object MakeGenericAction(Type[] types)
{
  if (types.Length == 1)
  {
    return typeof(Action<>).MakeGenericType(paramTypes);
  }
  else if (types.Length ==2)
  {
    return typeof(Action<,>).MakeGenericType(paramTypes);
  }
  ..... And so on....
}
  

Это действительно работает, и достаточно просто, чтобы охватить мои сценарии, но это кажется действительно хакерским. Есть ли лучший способ справиться с этим?

Ответ №1:

В таком случае, да:

 Type actionType = Expression.GetActionType(types);
  

Проблема здесь в том, что вы, вероятно, будете использовать DynamicInvoke, который работает медленно.

Action<object[]> Затем доступ по индексу может превзойти Action<...> вызов, выполняемый с помощью DynamicInvoke

Комментарии:

1. Красивое, элегантное решение (или, по крайней мере, настолько, насколько могут быть отражающие дженерики)

2. Очень приятно. Что бы произошло, если бы в вашем массиве было более 16 типов? Кроме того, что полиция кода удаляет у вас все электронные устройства.

3. @IndigoDelta винтики выпадут; p

4. Фантастика! Я бы никогда не нашел это самостоятельно. Я должен указать, что там также есть ‘GetFuncType’.

5. @Marc: Хорошая мысль. Кроме того, скрипт сборки, который создает эту часть фреймворка, автоматически проверяет, были ли добавлены новые типы действий, и соответствующим образом регенерирует код, поэтому у нас есть основания полагать, что это продолжит давать хорошие результаты, даже если мы добавим больше типов действий в будущем!

Ответ №2:

 Assembly asm = typeof(Action<>).Assembly;
Dictionary<int, Type> actions = new Dictionary<int, Type>;
foreach (Type action in asm.GetTypes())
    if (action.Name == "Action" amp;amp; action.IsGenericType)
        actions.Add(action.GetGenericArguments().Lenght, action)
  

затем вы можете использовать actions словарь, чтобы быстро найти нужный тип:

 public Type MakeGenericAction(Type[] types)
{
  return actions[types.Lenght].MakeGenericType(paramTypes);
}