Чистый способ передачи перечисления в функцию с возможностью передачи пустого значения в C # - PullRequest
1 голос
/ 18 февраля 2010

У меня есть объект, который представляет физическую структуру (например, вспомогательный столб), и он касается множества других объектов (проводов на полюсе). Другие объекты имеют ряд характеристик (состояние, размер, напряжение, фаза и т. Д.), Выраженных в виде перечислений. Я хочу написать универсальную функцию, которая подсчитывает, сколько проводов соответствует какой-либо или всем характеристикам.

Если бы перечисления были первоклассными объектами, я бы просто написал так:

class Wire
{
    public EStatus Status { get; set; }
    public ESize Size { get; set; }
    public EVoltage Voltage { get; set; }
    public EPhase Phase { get; set; }
}

int CountWires(EStatus status, ESize size, EVoltage voltage, EPhase phase)
{
    int count = 0;
    foreach (Wire wire in _connectedWires)
    {
        if (status != null && wire.Status != status) continue;
        if (size != null && wire.Size != size) continue;
        //...
        ++count;
    }
    return count;
}

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

CountWires(EStatus.New, ESize.Large, null, null);

... но, конечно, я получаю ошибку cannot convert from '<null>' to 'EVoltage'.

В прошлом мы решали эту проблему, добавляя значение «Any» к самим перечислениям и проверяя это, но затем, если мы сделаем что-то вроде отображения всех возможных значений в списке для пользователя, мы должны отфильтровать "Любой". Поэтому я хочу избежать этого.

Я подумал, что расскажу об этом сообществу и посмотрим, есть ли у кого-нибудь идеи, как сделать это с чистым интерфейсом и простым для чтения вызывающим кодом. У меня есть свой ответ, с которым я играю, и добавлю к обсуждению.

Ответы [ 6 ]

10 голосов
/ 18 февраля 2010

Или просто используйте обнуляемые типы.

int CountWires(EStatus? status, ESize? size, EVoltage? voltage, EPhase? phase)
{
    int count = 0;
    foreach (Wire wire in _connectedWires)
    {
        if (status.HasValue && wire.Status != status.Value) continue;
        if (size.HasValue && wire.Size != size.Value) continue;
        ...
        ++count;
    }
    return count;
}
4 голосов
/ 18 февраля 2010

ты пробовал нормальный обнуляемый? С чем? синтаксис довольно лаконичен (и в C # для него встроены неявные операторы)

CountWires(EStatus? status, ESize? size, EVoltage? voltage, EPhase? phase)

А использовать довольно просто

if (status.HasValue)
  stats.Value
2 голосов
/ 18 февраля 2010

Как насчет

CountWires(EStatus? status, ESize? size, EVoltage? voltage, EPhase? phase)
2 голосов
/ 18 февраля 2010

Разве вы не можете просто использовать

CountWires(EStatus? status, ESize? size, EVoltage? voltage, EPhase? phase)

Вам просто нужно сделать что-то подобное в начале функции CountWires, чтобы убедиться, что статус не равен NULL, когда ваш код выполняется

status = status ?? EStatus.DefaultValue;

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

0 голосов
/ 18 февраля 2010

В том же духе, мистер Джон Скит создал изящную библиотеку перечислений с ограничениями по типу под названием Unconstrained Melody .

0 голосов
/ 18 февраля 2010

Я экспериментирую с созданием класса NullableEnum:

class NullableEnum<T> where T : struct
{
    T _value;
    NullableEnum(T value) { _value = value; }
    public T Value { get { return _value; } }
}

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

CountWires(NullableEnum<EStatus> status,
           NullableEnum<ESize> size,
           NullableEnum<EVoltage> voltage,
           NullableEnum<EPhase> phase)

... но тогда код вызова должен выглядеть так:

CountWires(NullableEnum<EStatus>(EStatus.New), NullableEnum<ESize>(ESize.Large), null, null);

... что немного громоздко.

...