Есть ли название для этого шаблона?(Безопасность типов во время компиляции с аргументами "params" разных типов) - PullRequest
19 голосов
/ 03 августа 2011

Есть ли название для этого шаблона?

Допустим, вы хотите создать метод, который принимает переменное число аргументов, каждый из которых должен быть одним из фиксированного набора типов (в любом порядке или комбинации), а некоторые из этих типов вы не можете контролировать. Обычный подход заключается в том, чтобы ваш метод принимал аргументы типа Object и проверял типы во время выполнения:

void MyMethod (params object[] args)
{
    foreach (object arg in args)
    {
        if (arg is SomeType)
            DoSomethingWith((SomeType) arg);
        else if (arg is SomeOtherType)
            DoSomethingElseWith((SomeOtherType) arg);
        // ... etc.
        else throw new Exception("bogus arg");
    }
}

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

void MyMethod (params MyArg[] args)
{
    // ... etc.
}

struct MyArg
{
    public readonly object TheRealArg;

    private MyArg (object obj) { this.TheRealArg = obj; }

    // For each type (represented below by "GoodType") that you want your 
    // method to accept, define an implicit cast operator as follows:

    static public implicit operator MyArg (GoodType x)
    { return new MyArg(x); }

}

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

Я уверен, что другие использовали этот подход, поэтому мне интересно, есть ли название для этого шаблона.

Ответы [ 3 ]

3 голосов
/ 12 августа 2011

Похоже, что в Interwebs нет названного шаблона, но на основании комментария Ryan к вашему вопросу, я голосую, что имя шаблона должно быть Variadic Безопасность типов .

Как правило, я бы использовал это очень экономно, но я не оцениваю шаблон как хороший или плохой.Многие из комментаторов хорошо зарекомендовали себя за и против, что мы видим и для других шаблонов, таких как Factory , Сервисный локатор , Внедрение зависимостей , MVVM и т. Д. Все дело в контексте.Итак, вот удар по этому ...

Контекст

Переменный набор разнородных объектов должен быть обработан.

Использовать когда

  1. Ваш метод может принимать переменное число аргументов разнородных типов, не имеющих общего базового типа.
  2. Ваш метод широко используется (т. Е. Во многих местах вкод и / или большое количество пользователей вашей платформы. Дело в том, что безопасность типов обеспечивает достаточно преимуществ, чтобы гарантировать ее использование.
  3. Аргументы могут быть переданы в любом порядке, но наборразнородных типов является конечным, и единственный набор, приемлемый для метода.
  4. Выразительность - ваша цель проектирования, и вы не хотите, чтобы пользователь возлагал ответственность за создание оболочек или адаптеров (см. Альтернативы ).

Реализация

Вы уже предоставили это.

Примеры

  • LINQ to XML (например, new XElement(...))
  • Другие сборщики, такие как thosкоторые строят параметры SQL.
  • Фасады процессора (например, те, которые могут принимать различные типы делегатов или объекты команд из разных сред) для выполнения команд без необходимости явного создания адаптеров команд.

Альтернативы

  • Адаптер .Примите переменное число аргументов некоторого типа адаптера (например, Adapter<T> или подклассов неуниверсального Adapter), с которым метод может работать для получения желаемых результатов.Это расширяет набор, который может использовать ваш метод (типы больше не являются конечными), но ничего не теряется, если адаптер делает все правильно, чтобы обработка продолжала работать.Недостатком является то, что пользователь несет дополнительное бремя определения существующих и / или создания новых адаптеров, что, возможно, отвлекает от намерения (то есть добавляет «церемонию» и ослабляет «сущность»).
  • Remove TypeБезопасность .Это влечет за собой принятие очень базового типа (например, Object) и размещение проверок во время выполнения.Бремя того, что нужно передать, передается пользователю, но код все еще выразителен.Ошибки не проявляются до времени выполнения.
  • Composite .Передайте один объект, который является составной частью других.Для этого требуется предварительная сборка вызова метода, но мы возвращаемся к использованию одного из приведенных выше шаблонов для элементов в сборной коллекции.
  • Свободный API .Замените одиночный вызов серией конкретных вызовов, по одному для каждого типа допустимого аргумента.Канонический пример: StringBuilder.
1 голос
/ 12 августа 2011

Это называется анти-паттерном, более известным как Полтергейст .

Обновление:

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

  1. Удаление класса MyArg
  2. , устраняющее необходимость приведения типов в вашем MyMethod
  3. добавит дополнительную безопасность типов времени компиляциив том случае, если вы попытаетесь вызвать метод со списком аргументов, которые вы не можете обработать, вы получите исключение компилятора.
0 голосов
/ 03 августа 2011

Это похоже на подмножество Composite Pattern . Цитата из Википедии:

Составной шаблон описывает, что группа объектов должна обрабатываться так же, как отдельный экземпляр объекта.

...