Количество параметров универсального типа ?

#c# #.net

#c# #.net

Вопрос:

Я ищу способ улучшить код следующей структуры:

 foreach (var operation in operations)
{
    if (IsTypeAndDoSomething<Type1>(operation))
    {
        Run((Type1)operation);
    }
    else if (IsTypeAndDoSomething<Type2>(operation))
    {
        Run((Type2)operation);
    }
etc.
  

Я бы предпочел избежать длинного списка else if блоков с практически одинаковым шаблоном повсюду.

В этом проекте мы создаем перегруженный метод Run для выполнения каждой операции. Когда выполняется список операций, нам нужно сначала определить тип каждой операции, а затем подготовить ее (часть doSomething), прежде чем запускать ее Run . В настоящее время повторяется еще один подход, если кажется необходимым.

Однако мне интересно, есть ли в C # какой-либо способ сделать приведенный выше код более «общим» без повторяющихся else if s.

Одна из идей заключалась в создании коллекции типов, например

Мне было интересно, есть ли какой-либо способ преобразовать список типов в параметры универсального типа?

 var types = new[] {typeof(Type1), typeof(Type1)};
  

Затем, когда мы добавим новую реализацию операции, мы можем просто добавить ее в эту коллекцию (вместо нескольких else if блоков у нас будет другой итератор).

Однако нам нужно было бы каким-то образом передавать каждый элемент как Tx:

 IsTypeAndDoSomething<Tx>
  

Кажется невозможным ссылаться на эти типы в параметре универсального типа (T). Я предполагаю, что это связано с тем, что это делается во время компиляции, а не во время выполнения.

Возможно ли это или рекомендуется другой шаблон?

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

1. Сопоставление с образцом?

2. Есть ли у вас контроль над Type1 и т. Type2 Д.? Можете ли вы добавить к ним методы и заставить их реализовать общий интерфейс? Если это так, вам следует использовать полиморфизм.

3. Почему бы не использовать полиморфизм? рефакторинг.guru/replace-conditional-with-polymorphism может быть связан с динамическим программированием или отражением.

4. Что IsTypeAndDoSomething именно делает?

5. Чтобы уточнить комментарий Cid — сопоставление шаблонов с использованием switch

Ответ №1:

Альтернативой сопоставлению шаблонов может быть использование шаблона visitor:

Вы вводите пользовательский интерфейс

 interface IOperationsVisitor<T> {
    T Visit(Type1 obj);
    T Visit(Type2 obj);
}
  

И добавьте метод Accept в базовый класс для ваших операций:

 T Accept(IOperationsVisitor<T> visitor) => visitor.Visit(this);
  

Затем вы просто реализуете интерфейс посетителя и вызываете Accept метод для своего объекта с объектом посетителя в качестве параметра.

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

Ответ №2:

Простое изложение вопроса помогло мне понять, что ответ заключается в преобразовании в неродовой метод, т.е.

  private bool IsTypeAndDoSomething(Type type, object operation)
  

С этим изменением тип обрабатывается во время выполнения, и поэтому можно заменить повторяющиеся совпадающие блоки else if на следующие:

             var types = new[] {   
                                        typeof(Type1),
                                        typeof(Type2)
                                    };

            foreach (var operation in operations)
            {
                foreach (var type in types)
                {
                    if (IsTypeAndDoSomething(type, operation))
                    {
                        Run(operations, (dynamic) operation);
                    }
                }
            }
  

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

1. Это кажется хуже, чем оригинал. Общий всегда предпочтительнее системы. Введите объект, когда у вас есть значение

2. Первоначальное требование здесь состоит в том, чтобы избежать длинного блока else if с повторяющимися другими ifs (каждый из которых отличается только по типу). Я не могу придумать общий способ сделать это (поскольку тип известен только во время выполнения), но я приветствую любые мысли. Я обновил свой пример кода выше, чтобы показать более полное решение.