С# - как проверить, соответствует ли значение байта каким-либо флагам в указанном перечислении флагов?

В С# я сохраняю значение перечисления флагов в базе данных в виде байта. Например, для следующего перечисления Flags:

[Flags]
public enum Options
{
    None = 0,
    First = 1,
    Second = 2,
    Third = 4
}

Если я хочу записать «Первый» и «Второй», я сохраняю это как байт «3» в поле «Параметры» записи в базе данных.

Итак, при использовании LINQ, как я могу проверить, соответствует ли значение в базе данных «любому» из параметров в аргументе, переданном как перечисление «Параметры», что-то вроде этого псевдокода:

    public static Something(Options optionsToMatch)
    {
       db.MyEntity.Get(a => a.options contains any of the options in optionsToMatch);

person Chris Halcrow    schedule 25.08.2016    source источник
comment
Почему за это проголосовали?   -  person Chris Halcrow    schedule 25.08.2016
comment
Разве наличие любого из вариантов не равнозначно отсутствию None ?   -  person Sehnsucht    schedule 25.08.2016
comment
Нет, я имею в виду, что если байт (a.options) представляет любую из опций, переданных в «optionsToMatch», то это должно быть совпадение   -  person Chris Halcrow    schedule 25.08.2016
comment
Это все еще совершенно неясно (по крайней мере, для меня); любое значение (может быть, кроме отрицательного) представляет параметр или комбинацию параметров и, таким образом, является совпадением   -  person Sehnsucht    schedule 25.08.2016


Ответы (2)


Вот код, который делает то, что вы хотите, перебирая перечисления (я взял этот ответ из здесь).

   static void Main()
    {
        //stand-in for my database
        var options = new byte[] { 1, 2, 3, 3, 2, 2, 3, 4, 2, 2, 1,5 };

        var input = (Options)5;

        //input broken down into a list of individual flags
        var optional = GetFlags(input).ToList();
        //get just the options that match either of the flags (but not the combo flags, see below)
        var foundOptions = options.Where(x => optional.Contains((Options)x)).ToList();
        //foundOptions will have 3 options: 1,4,1
    }

    static IEnumerable<Enum> GetFlags(Enum input)
    {
        foreach (Enum value in Enum.GetValues(input.GetType()))
            if (input.HasFlag(value))
                yield return value;
    }

ИЗМЕНИТЬ

Если вы также хотите найти 5 в этом примере (комбо опций), просто добавьте дополнительное или условие, подобное этому:

var foundOptions = options.Where(x => optional.Contains((Options)x) || input == (Options)x).ToList();
person Kolichikov    schedule 25.08.2016

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

[Flags]
enum opts : byte {
    A = 1 << 0,
    B = 1 << 1,
    C = 1 << 2,
    D = 1 << 3,
    //.. etc
}

Затем просто побитовое И и посмотрите, не равно ли оно 0

opts a = opts.A | opts.D;
opts b = opts.B | opts.C | opts.D;
var c = a & b; //D

if((byte)c!=0){
    // ... things
}
person moreON    schedule 25.08.2016
comment
Прежде всего, он уже правильно определил флаги, сделав именно то, что сделали вы. Преобразуйте свои параметры в байты, и вы заметите, что они равны 1,2,4,8. Единственное, что добавляет ваш метод, — это дополнительная умственная проверка для всех последующих разработчиков относительно того, что такое 2^3. Это также делает код громоздким, потому что, если «opts b» — это список из базы данных с несколькими сотнями результатов, вы предлагаете, чтобы код повторялся и побитово или все они, просто чтобы сравнить их с другим побитовым или? Весь смысл флагов в том, что побитовое или уже сделано за вас. - person Kolichikov; 25.08.2016
comment
Ха, так они и есть, я думаю, что неправильно понял 3 вместо 4. Плохо. - person moreON; 25.08.2016