我有一个包含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行来填充任务数组
答案 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
}
}
}
这种方法的想法你把不同经销商的不同逻辑放在分离的类中。因为所有经销商类都将继承相同的抽象类,所以您可以在集合中添加不同的经销商。
您已经拥有硬编码的枚举和通讯方法,您尝试将它们链接在一起。这种方法使得经销商收集使用很少出价