2013-01-09 40 views
1

在我的程序中,我有一個列表框,當用戶雙擊一個對象時,它會查看一個switch語句以查看應該發生的事件。隨着列表開始變大,我很好奇是否有辦法避免必須維護2個地方的對象列表(一次在列表中添加到列表框中,一次在switch語句中)。 有沒有辦法索引/讀取/存儲我的switch語句的各種情況,然後將其作爲對象添加到列表框中我如何從Switch語句存儲個案清單?

例子:?(不工作,只是一種理論)

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

顯示錯誤,指出'行動'期待';'。我的邏輯準確嗎?如果是這樣,爲什麼行動電話不正確?

+4

你的例子沒有意義。 – Hogan

+2

@Hogan,它例如什麼起毛想要實現:這是枚舉交換機的所有案件... –

+0

我明白你的意思,你要以編程方式生成在交換機的情況下,但實際上你應該不需要做這個。還有另一種方法可以做任何你想做的事情,比如選擇列表框的選定索引。 – Mitch

回答

4

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

switch(n)成爲

​​
+1

c#在哪裏?無論是在問題中,還是在答案中。我錯過了一個分號,但代碼僅用於說明。 – Tilak

+0

也許我錯了,我認爲'作爲行動'是一個VB的方式來施放。 – Hogan

+1

[如C#(http://msdn.microsoft.com/en-us/library/cscsdfbt(V = vs.71)的.aspx),'as'相當於'is' +如果不是鑄造空 – Tilak

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

不能枚舉*的switchcase正常代碼。

你可以改爲將switch替換爲「動作名稱」映射爲「動作處理程序」,而不是您可以重新使用此映射列出動作名稱列表框。請參閱Tilak的樣本答案。

*)如果你真的好奇,你可以列舉switch的選擇。 C#代碼轉換爲IL,IL可以用代碼讀取。因此,您可以通過IL獲取方法,爲IL編寫(或獲取現有的 - Parser for C#)解析器,並在方法內部找到switch的實現,並選擇所有案例。您甚至可以在構建時直接使用C#源代碼 - 但它比IL解析更加複雜。

1

這聽起來好像在你的交換機要改變很多病例數。如果這是真的,那麼你可能要考慮使用switch語句以外的機制。也許你想要像Alexi Levenkov建議的那樣做,然後遍歷存儲的Action名稱列表並執行關聯的處理程序。這樣,您將避免必須將操作名稱添加到操作映射,然後將其添加到交換機。

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代替或與抽象基類組合可以是有益的,太。這消除了所有操作都從同一個基類繼承的需求,因爲這有時會很不方便。但我忽略了這一點,以免更多地超出這個範圍。

+0

+1堅持開放/關閉原則。 –

+0

+1。完整的方法很好和詳細的解釋。我認爲這對於基本的開關來說是過分的,但是OP的情況聽起來像將從這裏顯示的更加結構化的方法中受益。 –

+0

謝謝您的信息。在這一點上,我顯然很頭痛,需要做更多的研究。不過謝謝你的推薦。 –