C# 如何存储Switch语句中的案例列表?

C# 如何存储Switch语句中的案例列表?,c#,arrays,winforms,loops,switch-statement,C#,Arrays,Winforms,Loops,Switch Statement,在我的程序中,我有一个列表框,当用户双击一个对象时,它会查看switch语句以查看应该发生什么事件。随着列表开始变大,我很好奇是否有办法避免在两个位置维护对象列表(一个是要添加到列表框的列表,一个是switch语句)。 有没有办法索引/读取/存储switch语句的各种情况,然后将它们作为对象添加到我的列表框中 示例:(不起作用,只是一个理论) 编辑: 继续我现在的字典推荐: public void SetDictionary() { //add entries to the

在我的程序中,我有一个列表框,当用户双击一个对象时,它会查看switch语句以查看应该发生什么事件。随着列表开始变大,我很好奇是否有办法避免在两个位置维护对象列表(一个是要添加到列表框的列表,一个是switch语句)。 有没有办法索引/读取/存储switch语句的各种情况,然后将它们作为对象添加到我的列表框中

示例:(不起作用,只是一个理论)

编辑:

继续我现在的字典推荐:

public void SetDictionary()
    {
       //add entries to the dictionary
        dict["cat"] = new Action(Cat);
        dict["dog"] = new Action(Dog);

        //add each dictionary entry to the listbox.
        foreach (string key in dict.Keys)
        {
            listboxTest.Items.Add(key);
        }                            
    }

     //when an item in the listbox is double clicked
     private void listboxTest_DoubleClick(object sender, EventArgs e)
     {
         testrun(listboxCases.SelectedItem.ToString());             
     }

     public void testrun(string n)
     {
         //this is supposed to receive the item that was double clicked in the listbox, and run it's corresponding action as defined in the dictionary.
         var action = dict[n] as Action action();
     }
我相信我上面的代码基本上是正确的,我理解它,但是行动路线: var action=dict[n]as action()


显示一个错误,说明“action”应为“;”。我在这里的逻辑正确吗?如果正确,为什么操作调用不正确?

是的,有一种方法可以通过制作lambdas字典来实现这一点

void Main()
{
  // set up your dictionary
  Dictionary<string,Action> myList = new Dictionary<string,Action> {
     { "one", () => { Console.WriteLine("One function"); } },
     { "two",  () => { Console.WriteLine("Two function"); }},
     { "three", () => { Console.WriteLine("Three function"); }}
  };

  // do a "switch" (that is invoke a function that corresponds to a name)
  myList["one"]();

  // loop the list of keys (that is get a list of all the names)
  foreach (string key in myList.Keys)
    Console.WriteLine(key);
}

还要注意——您可以像这样动态地添加到这个“开关”(这很酷,而且是经典的开关语句所不能做到的。)


是的,有一种方法可以做到这一点,那就是制作一本lambdas词典

void Main()
{
  // set up your dictionary
  Dictionary<string,Action> myList = new Dictionary<string,Action> {
     { "one", () => { Console.WriteLine("One function"); } },
     { "two",  () => { Console.WriteLine("Two function"); }},
     { "three", () => { Console.WriteLine("Three function"); }}
  };

  // do a "switch" (that is invoke a function that corresponds to a name)
  myList["one"]();

  // loop the list of keys (that is get a list of all the names)
  foreach (string key in myList.Keys)
    Console.WriteLine(key);
}

还要注意——您可以像这样动态地添加到这个“开关”(这很酷,而且是经典的开关语句所不能做到的。)


您不能用普通代码*枚举
开关的
大小写

相反,您可以将
开关
替换为“action name”到“action handler”的映射,这样您就可以在action name列表框中重用此映射。有关示例,请参阅Tilak的答案


*)如果你真的很好奇,你可以列举
开关的选项。C#代码被转换为IL,IL可以用代码读取。因此,您可以为方法获取IL,为IL编写(或获取现有)解析器,并在方法内部找到
开关的实现,选择所有情况。你甚至可以在构建时直接访问C源代码,但这比IL解析更复杂。

你不能用普通代码*枚举
开关的
大小写

相反,您可以将
开关
替换为“action name”到“action handler”的映射,这样您就可以在action name列表框中重用此映射。有关示例,请参见Tilak的答案

*)如果你真的很好奇,你可以列举
开关的选项。C#代码被转换为IL,IL可以用代码读取。因此,您可以为方法获取IL,为IL编写(或获取现有)解析器,并在方法内部找到
开关的实现,选择所有情况。您甚至可以在构建时直接访问C#source,但这比IL解析更复杂。

字典
是避免的方法<代码>字典。键
变成
列表框。项

开关(n)
变为

var action = dict[n] as Action
action();
字典
是避免的方法<代码>字典。键
变成
列表框。项

开关(n)
变为

var action = dict[n] as Action
action();

在我看来,你的交换机中的案例数量将发生很大变化。如果这是真的,那么您可能需要考虑使用一个非Switter语句的机制。也许您希望执行Alexi Levenkov建议的操作,然后迭代存储的操作名称列表并执行关联的处理程序。这样,您就不必将操作名称添加到操作映射,然后再将其添加到交换机。

我觉得您交换机中的案例数量将发生很大变化。如果这是真的,那么您可能需要考虑使用一个非Switter语句的机制。也许您希望执行Alexi Levenkov建议的操作,然后迭代存储的操作名称列表并执行关联的处理程序。这样,您就不必将操作名称添加到操作映射中,然后再将其添加到开关中。

我建议将操作移动到单独的类中。为您的操作创建一个基类,如下所示。我为表单添加了一个字段,因为您可能需要与表单交互。如果需要,还可以传入其他对象

internal abstract class Operation
{
    protected readonly MyForm form = null;

    protected Operation(MyForm form)
    {
        this.form = form;
    }

    public abstract String DisplayName { get; }

    internal abstract void Execute();
}
然后为每个操作派生一个类

internal sealed class DoThis : Operation
{
    internal DoThis(MyForm form) : base(form) { }

    public override String DisplayName
    {
        get { return "Do this!"; }
    }

    internal override void Execute()
    {
        // Code to do this. You can use this.form to interact with
        // your form from this operation.
    }
}

internal sealed class DoSomethingElse : Operation
{
    internal DoSomethingElse(MyForm form) : base(form) { }

    public override String DisplayName
    {
        get { return "Do something else!"; }
    }

    internal override void Execute()
    {
        // Code to do something else.
    }
}
现在,您可以将所有操作添加到列表框中

this.lsitBox.Items.Add(new DoThis(this));
this.lsitBox.Items.Add(new DoSomethingElse(this));
并设置“显示成员”属性

this.listBox.DisplayMember = "DisplayName";
最后在事件处理程序中执行所选操作

((Operation)this.listBox.SelectedItem).Execute();
这种模式在所有操作之间提供了清晰的分离,并使将来的扩展变得简单和清晰。例如,如果必须检查某个操作当前是否可用,则可以向所有操作添加属性
CanExecute
。或者,如果您必须支持本地化,则可以很容易地添加逻辑,以便在当前UI语言中显示操作的名称

另一个容易支持的场景是,如果您有一些所有操作都通用的代码,例如日志记录、安全检查、性能度量等等

internal abstract class Operation
{
    protected readonly MyForm form = null;

    protected Operation(MyForm form)
    {
        this.form = form;
    }

    public abstract String DisplayName { get; }

    protected abstract void ExecuteCore();

    internal void Execute()
    {
        Logger.Log("Executing operation " + this.DisplayName);

        try
        {
            this.ExecuteCore();

            Logger.Log("Executing operation " + this.DisplayName + " succeeded.");
        }
        catch (Exception exception)
        {
            Logger.Log("Executing operation " + this.DisplayName + " failed.", exception);

            throw;
        }
    }
}
请注意,现在必须重写
ExecuteCore()
,而不是
Execute()


最后一个想法——使用接口
IOOperation
或者与抽象基类结合使用也可能会有所帮助。这消除了所有操作都从同一基类继承的需要,因为这有时可能不方便。但我省略了这一点,以避免对其进行过度设计。

我建议将您的操作移动到单独的类中。为您的操作创建一个基类,如下所示。我为表单添加了一个字段,因为您可能需要与表单交互。如果需要,还可以传入其他对象

internal abstract class Operation
{
    protected readonly MyForm form = null;

    protected Operation(MyForm form)
    {
        this.form = form;
    }

    public abstract String DisplayName { get; }

    internal abstract void Execute();
}
然后为每个操作派生一个类

internal sealed class DoThis : Operation
{
    internal DoThis(MyForm form) : base(form) { }

    public override String DisplayName
    {
        get { return "Do this!"; }
    }

    internal override void Execute()
    {
        // Code to do this. You can use this.form to interact with
        // your form from this operation.
    }
}

internal sealed class DoSomethingElse : Operation
{
    internal DoSomethingElse(MyForm form) : base(form) { }

    public override String DisplayName
    {
        get { return "Do something else!"; }
    }

    internal override void Execute()
    {
        // Code to do something else.
    }
}
现在,您可以将所有操作添加到列表框中

this.lsitBox.Items.Add(new DoThis(this));
this.lsitBox.Items.Add(new DoSomethingElse(this));
并设置“显示成员”属性

this.listBox.DisplayMember = "DisplayName";
最后在事件处理程序中执行所选操作

((Operation)this.listBox.SelectedItem).Execute();
此模式在所有操作和决策之间提供了清晰的分离