2010-12-15 1 views
2

Как вы сравниваете перечисления с несколькими битами? Я должен пропустить что-то простое.Сравнение двух перечислений с побитовым для одного True результата?

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

Бонус: Мне бы хотелось использовать побитовые операторы здесь, чтобы сократить запрос linq (чтобы я реплицировал это 5 или 6 раз по разным свойствам). Я знаю, что это нелегко прочитать, но это действительно поможет производительности в том, что я делаю.

public enum Targets 
{ 
    NotSet = 0, 

    Anonymous = 1, 
    Everyone = 2 
    Adult = 4, 
    Child = 8, 

    LikesFishing = 16 
} 

У меня есть пользователи с несколькими целями установить:

var loggedInUser = new User() 
{ 
    Username = "eduncan911", 
    Targets = Targets.Everyone | Targets.Adult | Targets.LikesFishing 
};  

У меня есть статьи, установленные с несколькими различными целями:

var article1 = new Article() 
{ 
    Title = "Announcement for Parents and Children", 
    Targets = Targets.Adult | Targets.Child 
}; 

var article2 = new Article() 
{ 
    Title = "What fishing boat do you own?", 
    Targets = Targets.LikesFishing | Targets.Adult 
}; 

var article3 = new Article() 
{ 
    Title = "Be nice to your parents!", 
    Targets = Targets.Child 
}; 

Как бы запросить статей, которые 1 Target Набор бит который соответствует как минимум 1 цели указанного пользователя выше (1 или более)? Я должен вернуть первые две статьи, потому что они соответствуют Targets.Adult, но loggedInUser.Targets не соответствует ни одному бит в 3-м наборе целей.

Я знаю, что могу запросить статьи для определенного типа Enum, как это:

var articles = 
    db.Articles.Where(x => x.Targets.HasFlag(Targets.LikesFishing); 

Но, у меня нет одной цели - у меня есть несколько битов набора. Следовательно, передача только «loggedInUser.Targets» никогда не будет соответствовать ни одному, поскольку сохраненное значение является просто int.

Сначала я запрашивая перечисления как это:

// returns a collection of enums the user has set 
// in their profile. 
var loggedInUserEnums = 
    Enum.GetValues(typeof(Targets)) 
    .Cast<Targets>() 
    .Where(x => loggedInUser.Targets.HasFlag(x)); 

Но при сравнении коллекции в другую коллекцию, что установила статьи, я всегда получал обратно верен для каждой статьи. Кажется, я ухожу на ла-ла.

Есть ли побитовая операция, которую я могу передать в выражение linq db.Articles.Where (...), чтобы сравнить эти два?

Просто догадаться, но я замечаю, когда я запрашиваю для целей статьи, что у меня есть NotSet, возвращающий true, независимо от I ~ Targets.NotSet или нет. Странный.

+0

дополнительной пищи для размышлений: нужно ли цикл в loggedInUserEnums nd для каждого Enum? Мне кажется дорогостоящим, когда я думаю, что для этого должен быть побитовый запрос. – eduncan911 2010-12-15 22:47:42

+1

Можно ли предположить, что «Linq» означает linq to sql или какой-либо другой поставщик запросов к базе данных linq? – marr75 2010-12-15 22:52:53

+0

Прошу прощения. Я имею в виду «Лямбда», а не linq. – eduncan911 2010-12-15 23:09:20

ответ

6

, если вы хотите, чтобы увидеть статьи, где целью является либо LikesFishing или взрослых,

попробовать это:

var target = Targets.LikesFishing | Targets.Adult; 
var articles = db.Articles.Where(x => (int)(x.Targets & target) > 0); 

и о, да, добавьте [FlagsAttribute] в перечислении:

[Flags] 
public enum Targets 
{ NotSet = 0, Anonymous = 1, Everyone = 2, 
    Adult = 4, Child = 8, LikesFishing = 16 } 
0

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

[Flags] 
public enum Targets 
{ 
    NotSet = 0, 

    Anonymous = 1, 
    Everyone = 2 
    Adult = 4, 
    Child = 8, 

    LikesFishing = 16 
} 

секунд, ваш LINQ будет выглядеть следующим образом:

var articlesThatLikeFishing = db.Articles.Where(x => (x.Targets & Targets.LikesFishing) == Targets.LikesFishing) 
0

Я думаю, что вы имели в виду, чтобы украсить ваш Enum с декоратором флагами.

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

Вы можете написать методы, которые будут генерировать выражение, которое может обрабатывать ваш провайдер. Это, вероятно, где-то вдоль линий. Где (x => x.Targets == 1 || x.Targets = 3 или x.Targets = 5 ... и т. Д. Ваш код не будет выглядеть так, заметьте, потому что вы будете динамически генерировать выражение (это более сложная тема, см. статью this).

Вы можете, проще говоря, переместить перечисление целей на свой объект с идентификатором и описанием. присоединиться к этим с многим ко многим и запрос по этим

-1

Я буду использовать INT вместо перечисления, что-то вроде:.

class Program { 
    public const int NotSet = 1; 
    public const int Anonymous = 1 << 2; 
    public const int Everyone = 1 << 3; 
    public const int Adult = 1 << 4; 
    public const int Child = 1 << 5; 
    public const int LikesFishing = 1 << 6; 

    public static bool HasFlag(Article article, int flag) { 
     return (article.Targets & flag) != 0; 
    } 

    public static bool HasFlags(Article article, params int[] flags) { 
     foreach (int flag in flags) { 
      if ((article.Targets & flag) == 0) return false; 
     } 
     return true; 
    } 

    static void Main(string[] args) { 
     var article1 = new Article() { 
      Title = "Announcement for Parents and Children", 
      Targets = Adult | Child 
     }; 

     var article2 = new Article() { 
      Title = "What fishing boat do you own?", 
      Targets = LikesFishing | Adult 
     }; 

     var article3 = new Article() { 
      Title = "Be nice to your parents!", 
      Targets = Child 
     }; 

     List<Article> db = new List<Article>() { article1, article2, article3 }; 

     var articles = 
      db.Where(x => HasFlag(x, LikesFishing)); 

     foreach (Article article in articles) { 
      Console.WriteLine(article.Title); 
     } 
    } 
} 

class Article { 
    public string Title { get; set; } 
    public int Targets { get; set; } 
} 
Смежные вопросы