2010-09-19 3 views
1

Изначально у меня был следующий:Другого метода перебора перечисления

[Flags] 
public enum QueryFlag 
{ 
    None = 0x00, 
    CustomerID = 0x01, 
    SalesPerson = 0x02, 
    OrderDate = 0x04 
} 

Как флажки проверяется/снят, я хотел бы добавить/удалить флаги:

QueryFlag qflag; 

Моей идеи - когда пользователь нажимает кнопку «Поиск», я бы перебирал фактические флаги, установленные в qflag, чтобы изменить предложение .Where в моей LINQ to Sql. Однако Enum.GetValues(qflag.GetType()) возвращает все значения самого QueryFlag. Не полезно.

Мое решение:

class myForm : Form 
{ 
    List<QueryFlag> qflag = new List<QueryFlag>(); 

    private void chkOrderDate_CheckedChanged(object sender, EventArgs e) 
    { 
     if (chkOrderDate.Checked && !qflags.Contains(QueryFlag.OrderDate)) 
      qflags.Add(QueryFlag.OrderDate); 
     else 
      qflags.Remove(QueryFlag.OrderDate); 
    } 

    private void cmdSearch_Click(object sender, EventArgs e) 
    { 
     if (qflags.Count == 0) 
     { 
      rtfLog.AppendText("\nNo search criteria selected."); 
      return; 
     } 

     foreach (QueryFlag flag in qflag) 
     { 
      rtfLog.AppendText(string.Format("\nSearching {0}", flag.ToString())); 

      // add switch for flag value 
     } 
    } 
} 

public enum QueryFlag 
{ 
    CustomerID, 
    SalesPerson, 
    OrderDate 
} 

У меня есть 3 флажков и это работает без каких-либо проблем в этой точке. Но мне интересно, есть ли лучший способ выполнить эту итерацию.

ответ

1

То, как оно было изначально было правильным; вы просто перепутались с методом Enum.GetValues. Этот метод возвращает каждое определенное значение для определенного типа enum, да. Итак, что вы do с этим является обязательным для каждого значение против вашего enum значение, чтобы узнать, установлено ли заданное значение в пределах вашего значения.

То есть, вы должны сделать это:

private void chkOrderDate_CheckedChanged(object sender, EventArgs e) 
{ 
    if (chkOrderDate.Checked) 
    { 
     qFlag |= QueryFlag.OrderDate; 
    } 
    else 
    { 
     qFlag &= (~QueryFlag.OrderDate); 
    } 
} 

... и аналогично для других CheckBoxes. Затем, когда вы хотите перечислить какие флаги вы установили:

static IEnumerable<QueryFlag> GetFlags(QueryFlag flags) 
{ 
    foreach (QueryFlag flag in Enum.GetValues(typeof(QueryFlag))) 
    { 
     // Presumably you don't want to include None. 
     if (flag == QueryFlag.None) 
     { 
      continue; 
     } 

     if ((flags & flag) == flag) 
     { 
      yield return flag; 
     } 
    } 
} 

На самом деле, вы могли бы даже абстрагировать выше в удобный метод расширения для всех enum типов:

public static class FlagsHelper 
{ 
    // This is not exactly perfect, as it allows you to call GetFlags on any 
    // struct type, which will throw an exception at runtime if the type isn't 
    // an enum. 
    public static IEnumerable<TEnum> GetFlags<TEnum>(this TEnum flags) 
     where TEnum : struct 
    { 
     // Unfortunately this boxing/unboxing is the easiest way 
     // to do this due to C#'s lack of a where T : enum constraint 
     // (there are ways around this, but they involve some 
     // frustrating code). 
     int flagsValue = (int)(object)flags; 

     foreach (int flag in Enum.GetValues(typeof(TEnum))) 
     { 
      if ((flagsValue & flag) == flag) 
      { 
       // Once again: an unfortunate boxing/unboxing 
       // due to the lack of a where T : enum constraint. 
       yield return (TEnum)(object)flag; 
      } 
     } 
    } 
} 

Так что ваш cmdSearch_Click обработчик мог выглядеть следующим образом:

private void cmdSearch_Click(object sender, EventArgs e) 
{ 
    if (qFlag == QueryFlags.None) 
    { 
     rtfLog.AppendText("\nNo search criteria selected."); 
     return; 
    } 

    foreach (QueryFlag flag in qFlag.GetFlags()) 
    { 
     rtfLog.AppendText(string.Format("\nSearching {0}", flag.ToString())); 

     // add switch for flag value 
    } 
} 
+0

Это не позволит вам сбросить бит. Оригинал правильно протестировал свойство «Проверено». –

+0

@Ben: Хорошая добыча; это было просто глупое наблюдение с моей стороны. Я обновлю ответ. –

+0

@ Dan: спасибо ... не знаю, почему я не думал о сравнении флагов, установленных в 'qflag', с значениями перечисления. Имеет смысл. Я не думаю, что хочу идти по маршруту расширения - бокс/распаковка крайне непривлекателен для этого проекта; однако я буду помнить об этом, если возникнет такая необходимость. – IAbstract

0

короткий, сырный и неэффективный способ:

qflag.ToString().Split('|') 
+0

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

+0

Разбор строк назад к перечислениям может не продвинуться вперед, на данный момент я, вероятно, доберусь до слова «Словарь <строка, CheckBox>». С вызовом 'string.Trim()' брошен там где-то. –

+0

Да, но на самом деле в этот момент вы не пришли к решению о том, как раздуты, как то, что у OP уже было (с «List »)? Я думаю, что он действительно был примерно на 90% от того, что уже существует с его подходом [Flags]; он просто отбросил, когда пришло время перечислить * набор флагов. –

Смежные вопросы