使用变量作为带循环的名称的一部分

时间:2016-12-17 02:12:06

标签: c#

我有几个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();

但是太长了所以我想使用循环。

怎么了?

4 个答案:

答案 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中的值。