迭代枚举的其他方法

时间:2010-09-19 15:31:43

标签: c# .net enums

最初,我有以下内容:

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

选中/取消选中复选框后,我会添加/删除以下标志:

QueryFlag qflag;

我的想法 - 当用户单击“搜索”按钮时,我将迭代qflag中设置的实际标志,以修改LINQ to Sql中的.Where子句。但是,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个复选框,这对此没有任何问题。但我想知道是否有更好的方法来执行此迭代。

2 个答案:

答案 0 :(得分:1)

你原来的方式是正确的;你只是被Enum.GetValues方法搞砸了。此方法返回特定enum类型的每个定义值,是。所以你这个是检查特定的 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
    }
}

答案 1 :(得分:0)

简短,俗气,低效的方式:

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