C# 使用枚举项调用方法

C# 使用枚举项调用方法,c#,enums,C#,Enums,我有一个包含30项的枚举。每个项都有一个同名的对应函数。我希望能够通过在某个位置引用枚举来调用该函数 因此,如果enum[0]=Foo,我希望能够使用类似enum(0)(“foobar”)的东西调用Foo(字符串栏) 最后一点是,我将每个函数作为任务运行,如下所示: enum Test { AA, BB, CC, DD ....} tasks[0] = Task.Run(() => { prices[0] = AA("a string"); }); tasks[1] =

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

因此,如果
enum[0]=Foo
,我希望能够使用类似
enum(0)(“foobar”)的东西调用
Foo(字符串栏)

最后一点是,我将每个函数作为任务运行,如下所示:

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

我想我只是想让我的代码尽可能简洁,任务量可能会翻倍,我不想最后用60行来填充任务数组

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

  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");
字典操作=新建字典()
{
{Test.AA,(x)=>{return 5;}},
{Test.BB,(x)=>{return 15;}},
}; //x是你的字符串
var res=actions[Test.AA](“hello”);

我强烈建议使用内置构造-例如扩展方法和简单开关:

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"); 
              });
}
for(int i=0;i<30;i++)
{
任务[i]=任务。运行(()=>
{ 
价格[i]=((测试)i).GetPriceWithString(“字符串”);
});
}
您想要做的是使用反射,反射可以是一个强大的工具,但理想情况下只能作为最后手段使用,因为它将隐藏可能的编译时错误,并导致代码可读性降低


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

使用一组代理如何:

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);
        }
    }
}
使用系统;
使用System.Threading.Tasks;
命名空间控制台应用程序
{
班级计划
{
私有静态int AA(字符串a){返回0;}
私有静态int-BB(字符串a){return 1;}
私有静态int CC(字符串a){return 2;}
私有静态Func[]函数=新的Func[]{AA,BB,CC};
私有静态int[]价格=新int[functions.Length];
私有静态任务[]任务=新任务[functions.Length];
静态void Main(字符串[]参数)
{
对于(int i=0;i{prices[i]=functions[i](“字符串”);});
Task.WaitAll(任务);
}
}
}

一个例子所说的远不止是文字

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

另一个解决方案。我希望有人会认为这是过火的行为) 创建抽象类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();
}
您可以创建
BindingList
并将其设置为
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
        }
    }       
}
公共类YourForm:Form
{
公共表格
{
初始化组件();
var交易商=新名单
{
新的Dealer1(),
新经销商2()
};
var bindSource=新绑定列表(经销商);
dataGridView.DataSource=bindSource;
}
//添加按钮,更新所有经销商的价格
私有无效按钮更新价格\u单击(对象发送者,事件参数e)
{
变量交易商=(BindingList)dataGridView.DataSource;
foreach(交易商中的var交易商)
{
dealer.UpdatePrice();
//因为我们把“RaisePropertyChanged”称为
//价格设定器-价格将自动
//在DataGridView中更新
}
}       
}
这种方法的想法是,将不同经销商的不同逻辑放在单独的类中。因为所有经销商类都将从同一个抽象类继承,所以可以向集合中添加不同的经销商


您已经有了硬编码的枚举和相应的方法,尝试将它们链接在一起。这种方法使使用dealers collection little bid变得很容易

您可以通过反射来实现这一点,但是您真的确定将函数名存储在枚举中是一个不错的选择吗?您必须使用反射来根据基于枚举值名称的方法名来查找
MethodInfo
。然后可以使用反射来调用它。您可以将其封装在一个方法中,并通过传入枚举和参数来调用它。请注意,不同方法的参数不应不同。Noooooo!希望这不可能。这听起来像是XY的问题。你到底想达到什么目的?目前,您猜测一个enum和类似于enum的方法就是解决方案。但是如果我们知道你真正想做什么,可能会有一个更干净的方法。或者你可以创建一个
字典
查找并使用它。我假设它接受一个字符串参数并返回一个小数。@Igor:不要这样做。3年后,这个家伙将不再理解自己的源代码。代码期望输出,可能是十进制。
Func
可能是一个更好的选择,而不是
Action
。@Igor这只是一个例子,取决于OP想要实现什么。但是我同意回答这个问题应该有一个返回类型,我将编辑并可能使用
int
作为键?似乎枚举的唯一值是为functions@KMoussa枚举还与表单上的文本框和标签相关,枚举的位置与prices数组的位置相关
var dealers = new List<DealerBase>
{
    new Dealer1(),
    new Dealer2()
}

foreach(var dealer in dealers)
{
    dealer.UpdatePrice();
}
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));
    }  
}
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
        }
    }       
}