我有几个NumericUpDown对象。我需要将所有值保存到相应的变量中(在属性中)。我已经设置了一个循环,所以它更短但不起作用。
这是代码:
private void RefreshTimer_Tick(object sender, EventArgs e)
for (int Count = 11; Count <= 16; Count++)
{
Properties.Settings.Default.("_NW" + Count) = this.Controls.("NW" + Count).Value;
Properties.Settings.Default.Save;
}
长代码应如下所示:
Properties.Settings.Default._NW11 = NW11.Value;
Properties.Settings.Default._NW12 = NW12.Value;
Properties.Settings.Default._NW13 = NW13.Value;
Properties.Settings.Default._NW14 = NW14.Value;
Properties.Settings.Default._NW15 = NW15.Value;
Properties.Settings.Default._NW16 = NW16.Value;
Properties.Settings.Default.Save();
但是太长了所以我想使用循环。
怎么了?
答案 0 :(得分:1)
如果您正在考虑使用Reflection,请始终尝试寻找更多选项。
解决方案是阵列/列表。它们专为索引访问而设计,是您尝试实现的要求。但是要实现这一点,您需要重新构建现有的资源指针,以便在这样的数组/列表中进行初始化和组织。
1)对于您的设置,请使用单个System.Collection.Specialized.StringCollection,而不是几个单独的字符串设置。让第一个空着。
2)然后,将控件设置为数组。
List<Control> controlsArray = new List<Control>();
void FormLoad(...)
{
for (var i = 0; i < 11; i++)
controlsArray.Add(null); //Dummy values
controlsArray.Add(this.Controls.NW11);
controlsArray.Add(this.Controls.NW12);
controlsArray.Add(this.Controls.NW13);
controlsArray.Add(this.Controls.NW14);
controlsArray.Add(this.Controls.NW15);
controlsArray.Add(this.Controls.NW16);
}
3)然后你可以这样做:
private void RefreshTimer_Tick(object sender, EventArgs e)
{
for (int Count = 11; Count <= 16; Count++)
{
if (controlsArray[Count] == null)
continue; //To be on the safe side
Properties.Settings.Default._NW[Count] = controlsArray[Count].Value;
}
Properties.Settings.Default.Save(); //Do this after the assignment loop has finished
}
4)如果您有更多控件,并且需要在编码中经常重复此模式,那么您可以更好地自动执行步骤[2]。
List<Control> controlsArray = new List<Control>();
void FormLoad(...)
{
foreach (var control in this.Controls)
{
if (control.Name.StartsWith("NW") == false)
continue;
var numberString = control.Name.SubString(2, control.Name.Length - 2);
var controlNumber = int.Parse(numberString);
while (numberString > controlsArray.Count - 1)
controlsArray.Add(null);
controlsArray[controlNumber] = control;
}
}
但是对于这么小的问题,使用你的长解决方案更有意义。为什么要有所有这些代码(可能是两行,并不是那么简单地遵循它正在做的事情 - 以及为什么),当你可以明确的时候?
由你决定。
Anti-Reflection Rant
是的,你应该总是尽量避免反思。
即使是序列化/反序列化,答案也不是反思。您可以在编译时生成辅助函数,甚至可以在运行时生成序列化代理。当然更多的工作,但肯定更好。 Google的protobuf工具在设计时从协议文件生成代码文件。
即使是链接到现有的库。例如,您可以使用Mono.Cecil在运行时将所有私有接口转换为public,然后直接引用。
我希望你明白这一点。您并不总是拥有资源,但是当您可以避免反射时,它始终是最佳解决方案。
答案 1 :(得分:0)
如果有人遇到同样的问题:代码工作只是提醒启用计时器...
代码:
private void RefreshTimer_Tick(object sender, EventArgs e)
{
for (int Count = 11; Count <= 16; Count++)
{
Properties.Settings.Default.("_NW" + Count) = this.Controls.("NW" + Count).Value;
Properties.Settings.Default.Save();
}
}
答案 2 :(得分:0)
你可以使用反射。像(未经测试)的东西:
for (int Count = 11; Count <= 16; Count++)
{
var property = Properties.Settings.Default.GetType().GetProperty("_NW" + Count);
var value = this.Controls["NW" + Count].Value;
property.SetValue (Properties.Settings.Default, propertyValue, null);
}
Properties.Settings.Default.Save;
其他方法,携带动态对象(如ExpandoObject
进行设置),然后最后在某一时刻将其保存到Settings
。此外,使用表达式树可以更快地进行属性设置反射。
答案 3 :(得分:0)
我进入了另一个论坛并问了同样的问题和正确的代码(最简单的)是:
private void Form1_Load(object sender, EventArgs e)
{
for (int Count = 11; Count <= 16; Count++)
{
((NumericUpDown)(Controls["NW" + Count])).Value = (decimal)Properties.Settings.Default["_NW" + Count];
}
}
private void RefreshTimer_Tick(object sender, EventArgs e)
{
for (int Count = 11; Count <= 16; Count++)
{
Properties.Settings.Default["_NW" + Count] = ((NumericUpDown)(Controls["NW" + Count])).Value;
}
Properties.Settings.Default.Save();
}
这将保存变量中的值,并在加载程序(或Form1)时加载NumericUPDown中的值。