选中复选框时如何遍历复选框并分配枚举值?

How to loop through check boxes and assign enumeration values when boxes are checked?

我有一组复选框,准确的说有3个复选框。它在使用 if 语句时对我有用,但我想知道是否有一种方法可以循环检查复选框并在选中一个或多个复选框时分配枚举值。

代码如下所示:

if (chkTomato.Checked && !chkLettuce.Checked && !chkCarrot.Checked)
{
    cart.VegChosen = Veggies.Tomato;
}
else if (!chkTomato.Checked && chkLecctuce.Checked && !chkCarrot.Checked)
{
    cart.VegChosen = Veggies.Lecctuce;
}
else if (!chkTomato.Checked && !chkLecctuce.Checked && chkCarrot.Checked)
{
    cart.VegChosen = Veggies.Carrot;
}
else if (chkTomato.Checked && chkLettuce.Checked && chkCarrot.Checked)
{
    cart.VegChosen = Veggies.All;
}
else if (chkTomato.Checked && chkLettuce.Checked && !chkCarrot.Checked)
{
    cart.VegChosen = Veggies.TomatoAndLettuce;
}
else if (chkTomato.Checked && !chkLettuce.Checked && chkCarrot.Checked)
{
    cart.VegChosen = Veggies.TomatoAndCarrot;
}
else if (!chkTomato.Checked && chkLettuce.Checked && chkCarrot.Checked)
{
    cart.VegChosen = Veggies.LettuceAndCarrot;
}
else
{
    cart.VegChosen = Veggies.None;
}

我想找到一种循环它的方法,以防超过 3 个复选框,if 语句会很长。

谢谢!

虽然这不使用循环,但我希望这就是您要实现的目标。假设您的枚举声明如下:

[Flags]
public enum Veggies
{
    None = 0,
    Tomato = 1,
    Lettuce = 2,
    Carrot = 4,
    TomatoAndLettuce = Tomato | Lettuce,
    TomatoAndCarrot = Tomato | Carrot,
    LettuceAndCarrot = Lettuce | Carrot,
    All = Tomato | Lettuce | Carrot
}

那么你应该可以使用类似的按位方法来赋值:

Veggies selectedVeggies = Veggies.None;
if (chkTomato.Checked)
{
    selectedVeggies = selectedVeggies | Veggies.Tomato;
}

if (chkLettuce.Checked)
{
    selectedVeggies = selectedVeggies | Veggies.Lettuce;
}

if (chkCarrot.Checked)
{
    selectedVeggies = selectedVeggies | Veggies.Carrot;
}

cart.VegChosen = selectedVeggies;

最终结果将与您当前的 if 语句集相同。我们使用 1、2、4 等作为枚举值的原因是因为当以二进制形式呈现时它们之间没有重叠(1 是 001,2 是 010,4 是 100,等等)所以特定的位可以只识别一个枚举值。

另请注意,TomatoAndLettuceTomatoAndCarrot 等声明可能也是不必要的,因为您可以使用 Enum.HasFlag().

例如:


var selectedVeggies = Veggies.Tomato | Veggies.Carrot;
// or var selectedVeggies = Veggies.TomatoAndCarrot; // effectively the same as above

if (selectedVeggies.HasFlag(Veggies.Tomato))
{
    cart.Add(new Tomato());
}

if (selectedVeggies.HasFlag(Veggies.Carrot))
{
    cart.Add(new Carrot());
}

// cart ends up with a Tomato and a Carrot

进一步阅读:What does the bitwise or | operator do?

像这样创建枚举:

enum Veggies {
    Tomato = 1 << 0,
    Lettuce = 1 << 1,
    Carrot = 1 << 2,
    All = Tomato | Lettuce | Carrot

}

这使得 Veggies.Tomato = 1 的值是 0000 0001Veggies.Lettuce = 20000 0010Veggies.Carrot = 40000 0100.

重要的是将枚举值转换为 1(2 的幂),这样您以后就可以将两个枚举值合并为一个 int,就像我对 Veggies.All 所做的那样,这是 0000 0111.

VegChosen 更改为 int,然后只需将您的代码更改为类似这样的按位或将枚举值更改为 VegChosen int:

cart.VegChosen = 0;

if(chkTomato.Checked) cart.VegChosen |= Veggies.Tomato;
if(chkLettuce.Checked) cart.VegChosen |= Veggies.Lettuce;
if(chkCarrot.Checked) cart.VegChosen |= Veggies.Carrot;

稍后,如果您想测试从 cart.VegChosen 中选择了哪些蔬菜,您可以按位并使用其中一个枚举值并检查它是否为 0,如下所示:

if((cart.VegChosen & Veggies.Carrot) != 0)
{
    //... cart.VegChosen contains Veggies.Carrot
}
if((cart.VegChosen & Veggies.Lettuce) != 0)
{
    //... cart.VegChosen contains Veggies.Carrot
}
//etc

这通常比 Enum.HasFlag() 的性能高出 ~50% faster/more,因为 HasFlag() 包含各种完整性检查,但如果您不是专门针对性能进行编程,那么最好使用更易于使用和阅读,在这方面我会推荐 Llama 的答案。

一旦你实现了 Llamas 的答案,即制作一个标志枚举,你就可以将所有复选框放在一个组框中,然后执行以下操作:

var veg = Veggies.None:
groupbox.Controls
  .OfType<CheckBox>()
  .Where(c => c.Checked)
  .ToList()
  .ForEach(c => veg |= Enum.Parse<Veggies>(c.Name[3..]));

然后您所要做的就是添加更多枚举成员并添加更多复选框,其中复选框名称类似于“chkXXX”,其中 xxx 是枚举成员的名称

这是一个循环构造:它获取组框上的所有控件并过滤为仅那些类型为复选框的控件,然后将其减少为仅选中的复选框。它把它变成一个列表(所以我们可以 foreach 它,因为 foreach 是一个列表而不是 LINQ 的东西)。 Foreach 将访问每个复选框并询问它是否被选中,它会将现有标志枚举值与将复选框名称(删除前 3 个字符)解析为 Veggies 的结果进行或运算。最后,您的 veg 变量将代表所有已选中的复选框

请注意,使用范围甚至 Enum.Parse<T> 需要相当现代的 c# 版本 - 如果您 运行 是不支持范围的版本,您可以使用 Substring(3)。您应该确保所有复选框名称都与您的枚举名称对齐。如果你想获得真正的技巧,你可以通过枚举枚举动态创建复选框并将枚举值作为复选框标签,当你将控件添加到表单时(动态地,在递增位置)这样你的表单将自动适应不管你有多少枚举成员