如何从Switch Statement中存储案例列表?

时间:2013-01-09 18:58:09

标签: c# arrays winforms loops switch-statement

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

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

Switch (n)
ForEach (Case c in Cases)
{
   arrayCases.Add(c);
}
listbox.Items.AddRange(arrayCases);

编辑:

继续我现在的词典推荐:

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();

显示错误,指出'action'期待';'。我的逻辑在这里准确吗?如果是这样,为什么动作调用不正确?

5 个答案:

答案 0 :(得分:4)

Dictionary<string, Action>是避免的方法。 Dictionary.Keys变为ListBox.Items

switch(n)变为

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

答案 1 :(得分:3)

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

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()

最后一个想法 - 使用接口IOperation代替或与抽象基类结合使用可能也会有所帮助。这消除了所有操作从同一基类继承的需要,因为这有时可能不方便。但是我省略了这一点,以免过度使用它。

答案 2 :(得分:2)

是的,有一种方法可以通过编写lambda字典来实现。

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);
}

该程序的输出:

One function
one
two
three

还要注意 - 你可以像这样动态添加到这个“开关”(这很酷,而且你不能用经典的switch语句做些什么。)

myList.Add("four",() => { Console.WriteLine("Four function is dynamic"); });

答案 3 :(得分:2)

您无法*使用普通代码枚举case switch

您可以做的是将switch替换为“动作名称”地图到“动作处理程序”,并且您将能够将此地图重新用于动作名称列表框列表。请参阅Tilak的答案以获取样本。

*)如果你真的好奇,你可以列举switch的选择。 C#代码转换为IL,IL可以用代码读取。因此,您可以获取IL的方法,为IL编写(或获取现有的 - Parser for C#)解析器并在方法中查找switch的实现,选择所有情况。你甚至可以在构建时直接使用C#源代码 - 但它比IL解析更加复杂。

答案 4 :(得分:1)

听起来我的开关中的案例数量会发生很大变化。如果这是真的,那么您可能需要考虑使用switch语句以外的机制。也许你想做像Alexi Levenkov建议的那样,然后迭代存储的Action Names列表并执行相关的处理程序。这样您就可以避免将操作名称添加到操作映射中,然后将其添加到交换机中。