Пометить Enum и взаимоисключающее Enum с перекрывающимся значением

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

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

Я унаследовал базу данных SQL, в которой состояние хранится как целое число, представляющее побитовые флаги. Я должен вызвать процедуру, которая выполняет сопоставление с побитовой операцией:

CREATE PROCEDURE SearchByState
    @MatchingStates       int
AS
BEGIN
    SELECT Id, State
    FROM Records
    WHERE @MatchingStates & State > 0
END;
GO

Меня это все устраивает.

Теперь, в реализации C#, совершенно ясно, что я должен определить флаги для представления комбинации совпадающих состояний в запросе:

[Flags]
public enum States
{
    None = 0x0,
    New= 0x1,
    InProgress = 0x2,
    Closed = 0x4,
    All = New | InProgress | Closed
}

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

Вопрос в том, каким должен быть тип свойства State модели этой записи:

1) Просто используйте флаги перечисления:

public class Record
{
    public int Id { get; set; }

    // Must ensure the value is equal to one of
    // States.New, States.InProgress, or States.Closed
    public States State { get; set; }
}

2) Определите новый тип перечисления для взаимоисключающего состояния:

public enum State
{
    New,
    InProgress,
    Closed
}

public class Record
{
    public int Id { get; set; }

    // Must be stored as the value of one of 
    // States.New, States.InProgress, or States.Closed
    public State State { get; set; }
}

Недостаток № 1 носит семантический характер: перечисление States представляет собой комбинацию состояний, а не одно состояние.

Недостаток № 2 практический: при сохранении состояния я должен определить базовое значение, которое нужно сохранить.

Можете ли вы придумать способ представить все это, сведя к минимуму эти недостатки?


person Ed I    schedule 12.10.2010    source источник


Ответы (2)


Я бы оставил его как одно перечисление без флагов.

Когда вы передаете это своей процедуре, вы можете построить целое число из перечисления, используя побитовое или (|), или даже просто добавить значения (приведение к int). Я бы постарался не «сломать» вашу логику, чтобы заставить работать один устаревший запрос, а вместо этого переработать код, вызывающий запрос, для обработки необычных требований.

Это сохраняет код чистым везде. «Состояние» в вашем случае не должно быть перечислением флагов — возможно только одно состояние.

person Reed Copsey    schedule 12.10.2010
comment
Также обратите внимание, что OP потребуется дополнительная проверка в своем установщике, а не использование автоматического свойства, если они хотят применить это. С примером кода из вопроса ничто не мешает мне сделать что-то вроде myRecord.State = (State)123456; - person LukeH; 13.10.2010
comment
@LukeH: Верно, но это верно для любого типа перечисления, перечисления флагов или нет. - person Reed Copsey; 13.10.2010

Я бы выбрал вариант № 2, а затем изменил ваши операторы Get/Set, чтобы каждый раз определять базовое значение. Таким образом, это делается для вас каждый раз, когда вы вызываете свойства. Код один раз, и все готово.

person pattertj    schedule 12.10.2010