简体   繁体   English

除了为多个if语句之外,是否还有一种更为优雅的方法来为被选中的多个复选框编写逻辑?

[英]Is there a more elegant way to write logic for multiple checkboxes being checked other than multiple if statements?

I am writing a windows forms application that has 4 check boxes that can be checked at the same time. 我正在编写一个Windows窗体应用程序,该应用程序具有可以同时选中的4个复选框。 I want to check to see what boxes are checked and do specific logic based on which boxes are checked. 我想检查一下选中了哪些框,并根据选中的框做特定的逻辑。 The issue being that if I end up trying to write code to check each possible combination of the check boxes I would have to write a long list of if else statements, and that is without checking for if there is only one checked. 问题是,如果我最终尝试编写代码来检查复选框的每个可能组合,则必须编写一长串if else语句列表,而这不会检查是否只有一个被选中。 Is there any more elegant way to check whether or not multiple check boxes are checked? 有没有更优雅的方法来检查是否选中了多个复选框? or am I stuck using if-else logic? 还是我坚持使用if-else逻辑?

//This is the type of code I am trying to avoid
//check all the conditions
//check1 is a check to add keys
//check2 is to create docs
//check3 is to create keys
//check4 is to reorder keys
//createKeys() creates keywords
//createDocs() creates documents
//addKeys() adds keywords
//reorderKeys reorders the keywords
if(check1 && check2 && check3 && check4){
    createKeys();
    createDocs();
    addKeys();
    reorderKeys();
}
else if(check1 && check2 && check3){
    createKeys();
    createDocs();
    addKeys();
}
else if(check1 && check2 && check4){
    createDocs();
    addKeys();
    reorderKeys();
}
else if(check1 && check2){
    createDocs();
    addKeys();
}
else if(check1){
    addKeys();
}
else if(check2 && check3 && check4){
    createKeys();
    createDocs();
    reorderKeys();
}
else if(check2 && check4){
    createDocs();
    reorderKeys();
}
else if(check2){
    createDocs();
}
else if(check3 && check4){
    createKeys();
    reorderKeys();
}
else if(check3){
    createKeys();
}
else if(check4){
    reorderKeys();
}

Code update to be more specific 代码更新更具体

An alternative to if/else would be a method table. if/else的替代方法是方法表。 You can create a dictionary and put all code as Action 您可以创建一个词典并将所有代码放入Action

var methodTable = new Dictionary<(bool, bool, bool, bool), Action>
{
    [(false, false, false, true)] = () => { /* do something */ },
    [(false, false, true, false)] = () => { /* do something else */ },
    [(false, false, true, true)] = SomeClassMethod,
    // and so on
};

Now you can invoke code from if/else block with single line: 现在,您可以单行从if/else块调用代码:

methodTable[(check1, check2, check3, check4)].Invoke();

EDIT 编辑

If there is some combination of checkboxes you do not want to process you have to options: 如果复选框的某种组合不希望您处理,则必须选择:

Add empty handlers to methodTable like: 将空处理程序添加到methodTable如下所示:

[(false, false, false, true)] = () => {}, // do nothing

Or (which is better for me) use TryGetValue method: 或者(对我来说更好)使用TryGetValue方法:

if (methodTable.TryGetValue((check1, check2, check3, check4), out var method))
    method.Invoke();

Use an enumeration : 使用枚举:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication46
{
    public partial class Form1 : Form
    {
        enum CheckBoxEnum
        {
            CHECKBOXNONE = 0,
            CHECKBOX1 = 1,
            CHECKBOX2 = 2,
            CHECKBOX3 = 4,
            CHECKBOX4 = 8,
        }

        List<CheckBox> checkboxes;
        CheckBoxEnum boxEnum = CheckBoxEnum.CHECKBOXNONE;
        public Form1()
        {
            InitializeComponent();

            checkboxes = new List<CheckBox>() { checkBox1, checkBox2, checkBox3, checkBox4 };

            foreach (CheckBox box in checkboxes)
            {
                box.Click += new EventHandler(box_Click);
            }

            switch (boxEnum)
            {
                case CheckBoxEnum.CHECKBOX1 | CheckBoxEnum.CHECKBOX3 :
                    break;
            }





        }
        private void box_Click(object sender, EventArgs e)
        {
            CheckBox box = sender as CheckBox;
            if (box.Checked)
            {
                boxEnum |= (CheckBoxEnum)(1 << checkboxes.IndexOf(box));
            }
            else
            {
                boxEnum &= ~(CheckBoxEnum)(1 << checkboxes.IndexOf(box));
            }
        }
    }
}

( I know you already have an answer, consider this option as a possible alternative in another occasion ). 我知道您已经有了答案,请考虑在其他情况下将此选项作为替代方法 )。

You can associate a specific Action with a Control or a collection of controls, then perform all the associated actions when it's required, triggering the actions in a sequence. 您可以将特定的动作与某个控件或一组控件关联,然后在需要时执行所有关联的动作,并按顺序触发这些动作。 A specific sequence, if required, as it is here. 如果需要,请按照此处的顺序进行操作。

For example, your createKeys() method has a higher priority when selected, createDocs() one level less, but it must be executed before the others when those are active too and so on. 例如,您的createKeys()方法在被选择时具有较高的优先级,而createDocs()优先级要一个级别 ,但是当它们也处于活动状态时,它必须在其他级别之前执行。

So, using a manager class, you can associate all the actions (method calls) to the state of a Control, define the Action priority, then perform all the actions in one call when a conditon changes (a CheckBox is selected, a Button is clicked etc.). 因此,使用管理器类,您可以将所有动作(方法调用)与控件的状态相关联,定义动作优先级,然后在条件改变时(选择一个CheckBox,一个Button为点击等)。

Using the ActionManager class, you can associate Actions to Controls, add them to the class then call PerformActions() to execute all the active method: 使用ActionManager类,可以将Actions与Controls关联,将它们添加到类中,然后调用PerformActions()来执行所有活动方法:

ActionManager.Actions.AddRange(new[] {
    new ActionManager.ActionControl(() => CreateKeys(), this.chkCreateKeys, 1),
    new ActionManager.ActionControl(() => CreateDocs(), this.chkCreateDocs, 2),
    new ActionManager.ActionControl(() => AddKeys(), this.chkAddKeys, 3),
    new ActionManager.ActionControl(() => ReorderKeys(), this.chkReorderKeys, 4)
});

When needed, just call: 需要时,只需致电:

 ActionManager.PerformActions(); 

and all methods are executed. 并执行所有方法。

This is how it performs, on a CheckedChanged event (could be a Button click or anything else): 这是在CheckedChanged事件(可以是Button单击或其他任何事件)上的执行方式:

CheckBox Manager类别

ActionManager class: ActionManager类:

public class ActionManager
{
    public static List<ActionControl> Actions { get; set; } = new List<ActionControl>();
    public static void PerformActions() {
        var sequence = Actions.Where(c => c.Control.Checked).OrderBy(a => a.ActionPriority);
        foreach (var action in sequence) {
           action.Action?.Invoke();
        }
    }
    public class ActionControl
    {
        public ActionControl(Action action, CheckBox control, int priority) {
            this.Action = action;
            this.Control = control;
            this.ActionPriority = priority;
        }
        public Action Action { get; }
        public CheckBox Control { get; }
        internal int ActionPriority { get; }
    }
}

We'll be using sets of numbers representing which checkboxes are set, so {1, 3} means check1 && check3 . 我们将使用代表设置了哪些复选框的数字集,因此{1, 3}表示check1 && check3

If all the logic is completely separate, ie there is no connection between actions taken for {a_1, a_2, ..., a_n} and {a_1, a_2, ..., a_n, x} for any a_1, ..., a_n and x , then obviously you need to have 2^n separate procedures for each combination. 如果所有逻辑都是完全分开的,即,对{a_1, a_2, ..., a_n}采取的行动与对任何a_1, ..., a_n {a_1, a_2, ..., a_n, x}采取的行动之间没有联系a_1, ..., a_nx ,那么显然每个组合都需要2^n独立的过程。 That means that either way we have to branch into 2^n different code flows. 这意味着无论哪种方式,我们都必须分支为2^n不同的代码流。 So the question boils down to whether we can decide which set to use in a less code consuming way. 因此,问题归结为我们是否可以以较少的代码消耗方式决定使用哪个集合。

Obviously, you need to somehow wire up behaviour to different sets. 显然,您需要以某种方式将行为绑定到不同的集合。 That means that no matter what we do, under the assumption that we can have 2^n completely unrelated procedures, one for each set, you still have to have at least 2^n statements that will link a particular set to a particular procedure. 这意味着无论我们做什么,在假设我们可以有2^n完全不相关的过程(每个集合一个)的假设下,您仍然必须至少有2^n语句将特定集合链接到特定过程。 So the short answer is no, even if you got rid of if/else statements, for example encoding the checks as sequences of bits and then mapping these sequences to procedures, you'd get rid of the logic here, but somewhere else in the code you'd have to have mappings like: 因此,简短的答案是“否”,即使您摆脱了if/else语句,例如将支票编码为位序列,然后将这些序列映射到过程,也可以摆脱这里的逻辑,但可以摆脱代码,您必须具有以下映射:

Dictionary<string, Action> logic = new Dictionary<int[], Action>();

logic["{1}"] = DoStuffFor1;
logic["{2}"] = DoStuffFor2;
...
logic["{N}"] = DoStuffForN;
logic["{1, 2}"] = DoStuffFor12;
logic["{1, 3}"] = DoStuffFor13;
...

var checkboxSet = Encode(check1, check2, ..., checkN); // Implementation of Encode should be obvious.
logic[checkboxSet].Invoke();

so still 2^n statements. 所以还是2^n语句。 Thus, for a general case there's no way of decreasing the number of lines you write, but you might find a map of delegates more elegant than a swarm of if/else statements. 因此,在一般情况下,无法减少编写的行数,但您可能会发现委托映射比大量的if/else语句更为优雅。

If, however, the logic for different sets of checkboxes is interconnected somehow, which will be the case in any reasonable real life application, you could probably collapse the if statements to shorten the code. 但是,如果不同复选框的逻辑以某种方式互连(在任何合理的实际应用程序中都是这种情况),则可能会折叠if语句以缩短代码。 But without more details about the actual logic of the program it's impossible to tell. 但是,如果没有有关程序实际逻辑的更多细节,就不可能说出来。

EDIT: 编辑:

Actually, now that I come to think of it, you could have a very convoluted way of resolving a method name at runtime using reflection, and by using a naming convention for your methods so that the names for all handlers are nonambiguous (for example a method handling {1, 42, 100} would be named DoStuffFor_1_42_100 etc.) you could fetch a method with name equivalent to the checked checkboxes and invoke it. 实际上,现在我想到了,您可以采用一种非常费解的方法,在运行时使用反射来解析方法名称,并为您的方法使用命名约定,以便所有处理程序的名称都是明确的(例如处理{1, 42, 100} DoStuffFor_1_42_100 {1, 42, 100}将被命名为DoStuffFor_1_42_100等。)您可以获取一个名称与选中的复选框等效的方法并调用它。 It would still require you to write the 2^n procedures, though. 但是,仍然需要您编写2^n过程。 Also I think we can unanimously agree that it's a terrible idea to use reflection for this thing and rely on a naming convention for the code to work. 同样,我认为我们可以一致同意,使用反射来实现这一目标并依靠命名约定来使代码正常工作是一个糟糕的主意。

For 4 checkboxes you can do something like this: 对于4个复选框,您可以执行以下操作:

Add them into array 将它们添加到数组中

bool[] checkboxes = { check1, check2, check3, check4 };

then select their 10 power by its indices, so you can use their Sum to get unique values for each one: 然后通过其索引选择10个幂,因此您可以使用它们的Sum来获得每个值的唯一值:

var selected = checkboxes
                     .Reverse() // reversing to get result with correct order
                     .Select((s, i) => new { IsChecked = s, Index = Math.Pow(10, i) })
                     .Where(w => w.IsChecked)
                     .Sum(s => s.Index);

so you will get 1100 for true, true, false, false , or 101 for false, true, false, true , etc. 因此对于true, true, false, false ,您将获得1100 ;对于false, true, false, truefalse, true, false, true您将获得101

and you can have Dictionary<double, Action> for all possibilities, like: 并且您可以使用Dictionary<double, Action>来处理所有可能性,例如:

Dictionary<double, Action> methods = new Dictionary<double, Action>
{
    { 0000,  YourMethod },
    { 0001,  YourMethod1 },
    { 0010,  YourMethod2 },
    { 0011,  YourMethod3  },
    { 0100,  YourMethod4  },
    { 0101,  YourMethod5  },
    { 0110,  YourMethod6  },
    { 0111,  YourMethod7  },
    { 1000,  YourMethod8  },
    { 1001,  YourMethod9  },
    { 1010,  YourMethod10  },
    { 1011,  YourMethod11  },
    { 1100,  YourMethod12  },
    { 1101,  YourMethod13  },
    { 1110,  YourMethod14  },
    { 1111,  YourMethod15  },
};

and call it like this: 并这样称呼它:

 methods[selected]();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 有没有更优雅的方法来汇总多个属性? - Is there a more elegant way to sum multiple properties? 编写决策代码的更优雅的方法是评估具有不同优先级的多个输入? - A more elegant way to write decision making code which evaluates multiple inputs with different priorities? 检查多个isValid语句的更紧凑方法 - More compact way of checking multiple isValid statements 有没有更优雅的方法来指定多个相同性质的一对多关系? - Is there a more elegant way to specify multiple one to many relations of same nature? 如何检查是否已选中多个复选框 - How to check if multiple checkboxes are checked 有没有更有效的方法来保存选中的复选框 state? - Is there a more efficient way of saving checkboxes checked state? 使用多个SwaggerRespons的优雅方式 - Elegant way to use Multiple SwaggerResponses 重写多个return语句的简便方法 - Easy way to re-write multiple return statements 是否有更优雅的方法来进行多个条件验证 - Is there more elegant method for multiple conditions verification 是否存在使用Entity Framework将多个参数传递给SQL存储过程的更简洁或更简洁的方法? - Is there a more cleaner or elegant way to pass multiple parameters to SQL stored procedure using Entity Framework?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM