2016-11-10 109 views
3

我有一個枚舉,其中有30個項目。每個項目具有相同的名稱相應的功能。我希望能夠通過在某個位置引用枚舉來調用該函數。使用枚舉項來調用方法

因此,如果在enum[0] = Foo的價值,我希望能夠通過使用類似enum(0)("foobar")

到底點我運行的每個功能,像這樣一個任務來調用Foo(string bar)

enum Test { AA, BB, CC, DD ....} 
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); }); 
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); }); 
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); }); 
//for 30 tasks 

我想什麼做的是沿着線的東西:

enum Test { AA, BB, CC, DD ....} 
for (int i = 0; i < 30; i++) 
{ 
    tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); }); 
} 
Task.WaitAll(tasks.ToArray()); 

難道這東西,是即便possibl è?

編輯:

枚舉涉及控件的窗體上,所以我有textboxs,標籤陣列和被填充了的函數的結果的價格的一個陣列:

enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 }; 

    static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length; 
    decimal[] prices = new decimal[noOfDealers]; 
    TextBox[] textBox = new TextBox[noOfDealers]; 
    Label[] boxes = new Label[noOfDealers]; 

    for (int i = 0; i < noOfDealers; i++) 
    { 
     textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox; 
     boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label; 
     prices[i] = 0; 
    } 

    //RUN 30 TASKS TO POPULATE THE PRICES ARRAY 

    for (int i = 0; i < noOfDealers; i++) 
    { 
     textBox[i].Text = "£" + prices[i].ToString(); 
    } 

    //LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS 

我猜我只是試圖讓我的代碼儘可能簡明,對於任務的一倍量的潛力,並沒有要結束了與60線填充任務陣列

+4

你可以通過反射來做到這一點,但你真的*確保將函數名存儲在一個枚舉中是一個不錯的選擇? – Lennart

+1

您將不得不使用反射來基於枚舉值的名稱找到基於方法名稱的「MethodInfo」。然後你可以使用反射來調用它。你可以把它包裝在一個方法中,並通過傳入枚舉和參數來調用它。請注意,這些參數在方法之間不應有差異。 – Igor

+1

Noooooo!希望這是不可能的。這聽起來像是一個XY問題。你真的想達到什麼目的?目前你猜測枚舉和類似枚舉的方法是解決方案。但如果我們知道你真正想做什麼,那麼可能會有更清潔的方法。 –

回答

6

我想創建字典和將枚舉映射到操作:

Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>() 
      { 
       {Test.AA, (x) => { return 5;}}, 
       {Test.BB, (x) => { return 15; }}, 
      }; //x is your string 

      var res = actions[Test.AA]("hello"); 
+0

代碼期待輸出,可能是小數。而不是'Action ','Func '可能是更好的選擇。 – Igor

+0

@Igor這只是一個例子,取決於他想要達到的目標。但同意回答這個問題應該有一個返回類型,我將編輯 – MistyK

+0

並且可能使用'int'作爲關鍵字?看起來,枚舉的唯一值是索引函數 – KMoussa

1

我會強烈建議使用內置的結構 - 比如一個擴展方法和一個簡單的開關:

public static int GetPriceWithString(this Test test, string str) 
{ 
    switch (test) 
    { 
     case Test.AA: 
      break; 
     case Test.BB: 
      break; 
     case Test.CC: 
      break; 
     case Test.DD: 
      break; 
     default: 
      throw new ArgumentOutOfRangeException(nameof(test), test, null); 
    } 
} 

那麼你的循環看起來幾乎是一樣的:

for (int i = 0; i < 30; i++) 
{ 
    tasks[i] = Task.Run(() => 
       { 
        prices[i] = ((Test)i).GetPriceWithString("a string"); 
       }); 
} 

什麼你想要做的事情可以用反射來實現,反射可以是一個強大的工具 - 但理想情況下只能作爲最後的手段使用,因爲它會隱藏可能導致編譯時錯誤的代碼,並導致代碼可讀性降低。

使用這樣一個簡單的開關可以讓您的代碼自動記錄,因此當您在一個月內回到這裏時,您可以快速記住它的用意。

1

如何使用委託的數組:

using System; 
using System.Threading.Tasks; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static int AA(string a) { return 0; } 
     private static int BB(string a) { return 1; } 
     private static int CC(string a) { return 2; } 

     private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC }; 
     private static int[] prices = new int[functions.Length]; 
     private static Task[] tasks = new Task[functions.Length]; 

     static void Main(string[] args) 
     { 
      for (int i = 0; i < functions.Length; ++i) 
       tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); }); 
      Task.WaitAll(tasks); 
     } 
    } 
} 
1

的如。說話遠不止言語。

我在一個winform中使用它,所以this是指贏的形式。 我假設你所有的方法都是公開的,具有相同的簽名&返回相同的類型。

enum MyName { AA,BB,CC}; 

//Call this in one of your methods 

    string [] strVal= Enum.GetNames(typeof(MyName)); 
       int x = CallFunction(strVal[0], "A"); 
       int y = CallFunction(strVal[1], "h"); 
       int z = CallFunction(strVal[1], "C"); 

//End Call this in one of your methods 


    int CallFunction(string strName,string strValue) 
      { 
       return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue })); 
      } 

    public int AA(string s) 
      { 
       return 1; 
      } 

      public int BB(string s) 
      { 
       return 2; 
      } 

      public int CC(string s) 
      { 
       return 3; 
      } 
1

另一種解決方案。我希望有人會認爲它是過度殺傷:)

創建抽象類DealerBase。

public abstract class DealerBase 
{ 
    public string Name { get; } 

    public decimal Price { get; set; } 

    protected DealerBase(string name) 
    { 
     Name = name; 
    } 

    public abstract void UpdatePrice(); 
} 

然後爲每個經銷商創建類併爲UpdatePrice方法實現自己的邏輯。

public class Dealer1 : DealerBase 
{ 
    public Dealer1() : base("DealerOne") { } 

    public override void UpdatePrice() 
    { 
     //Calculate price 
     Price = DealerOneCalculationMethod(); 
    } 
} 

public class Dealer2 : DealerBase 
{ 
    public Dealer2() : base("DealerTwo") { } 

    public override void UpdatePrice() 
    { 
     //Calculate price 
     Price = DealerTwoCalculationMethod(); 
    } 
} 

等等..

然後你只需創建經銷商可以是收集容易反覆

var dealers = new List<DealerBase> 
{ 
    new Dealer1(), 
    new Dealer2() 
} 

foreach(var dealer in dealers) 
{ 
    dealer.UpdatePrice(); 
} 

可以循環經銷商和生成文本框,在的WinForms標籤。

但我建議使用DataGridView代碼將會更清晰。 首先實現INotifyPropertyChanged接口的基類DealerBase

public abstract class DealerBase : INotifyPropertyChanged 
{ 
    public string Name { get; } 

    protected decimal _Price; 
    public decimal Price 
    { 
     get { return _Price; } 
     set 
     { 
      if (Equals(_Price, value)) return; 
      _Price = value; 
      // next method will inform DataGridView about changes 
      // and update value there too 
      RaisePropertyChanged();   
     } 

    protected DealerBase(string name) 
    { 
     Name = name; 
    } 

    public abstract void UpdatePrice(); 

    // Implementation of INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

中表格,您可以創建BindingList<DealerViewModelBase>並將其設置爲DataGridView.DataSource

public class YourForm: Form 
{ 
    public YourForm() 
    { 
     InitializeComponent(); 

     var dealers = new List<DealerBase> 
     { 
      new Dealer1(), 
      new Dealer2() 
     }; 

     var bindSource = new BindingList<DealerBase>(dealers); 
     dataGridView.DataSource = bindSource; 
    } 

    // Add button which update prices for all dealers 
    private void ButtonUpdatePrices_Click(object sender, EventArgs e) 
    { 
     var dealers = (BindingList<DealerBase>)dataGridView.DataSource; 
     foreach (var dealer in dealers) 
     { 
      dealer.UpdatePrice(); 
      // Because we call `RaisePropertyChanged` in 
      // setter of Price - prices will be automatically 
      // updated in DataGridView 
     } 
    }  
} 

知道這個方法你把不同經銷商的不同的邏輯在分開的課程。由於所有經銷商類都將繼承相同的抽象類,因此您可以向該集合中添加不同的經銷商。

你已經有硬編碼的枚舉和對應的方法,你試圖鏈接在一起。這種方法使得使用經銷商收集很少的出價很容易