2016-11-10 60 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 
     } 
    }  
} 

知道这个方法你把不同经销商的不同的逻辑在分开的课程。由于所有经销商类都将继承相同的抽象类,因此您可以向该集合中添加不同的经销商。

你已经有硬编码的枚举和对应的方法,你试图链接在一起。这种方法使得使用经销商收集很少的出价很容易