使用枚举项来调用方法

时间:2016-11-10 14:14:55

标签: c# enums

我有一个包含30个项目的枚举。每个项目都有一个具有相同名称的相应功能。我希望能够通过在某个位置引用枚举来调用该函数。

因此,如果enum[0] = Foo处的值,我希望能够使用Foo(string bar)

之类的内容来呼叫enum(0)("foobar")

最后要点是我将每个函数作为一个任务运行:

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

这有可能吗?

编辑:

枚举与表单上的控件有关,因此我有一组文本框,标签和一系列价格,这些价格填充了函数的结果:

    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行来填充任务数组

5 个答案:

答案 0 :(得分:7)

我会创建字典并将枚举映射到动作:

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

答案 1 :(得分: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"); 
              });
}

你想要做的是使用反射,这可以是一个强大的工具 - 但理想情况下应该只作为最后的手段,因为它将隐藏编译时错误,并导致更少的代码可读性。

使用这样的简单开关可以使您的代码自我记录,因此当您在一个月内回到此状态时,您可以快速记住其意图。

答案 2 :(得分: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);
        }
    }
}

答案 3 :(得分:1)

例如。说的不仅仅是文字。

我在winform中使用它,所以this指的是win形式。 我假设你的所有方法都是公开的,有相同的签名和返回相同的类型。

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

答案 4 :(得分: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
        }
    }       
}

这种方法的想法你把不同经销商的不同逻辑放在分离的类中。因为所有经销商类都将继承相同的抽象类,所以您可以在集合中添加不同的经销商。

您已经拥有硬编码的枚举和通讯方法,您尝试将它们链接在一起。这种方法使得经销商收集使用很少出价