【问题标题】:Is this an abuse of the Settings Feature?这是滥用设置功能吗?
【发布时间】:2010-12-04 10:43:46
【问题描述】:

我一直在 Properties.Settings.Default 对象中存储用户设置集合,并使用 Visual Studio 设置设计器(右键单击您的项目,单击属性,然后单击设置选项卡)进行设置。最近,一些用户抱怨此特定设置跟踪的数据随机丢失。

给出一个想法(不完全是我怎么做,但有点接近),它的工作方式是我有一个对象,像这样:

class MyObject
{
    public static string Property1 { get; set; }
    public static string Property2 { get; set; }
    public static string Property3 { get; set; }
    public static string Property4 { get; set; }
}

然后在代码中,我可能会做这样的事情来保存信息:

public void SaveInfo()
{
    ArrayList userSetting = new ArrayList();
    foreach (Something s in SomeCollectionHere) // For example, a ListView contains the info
    {
        MyObject o = new MyObject {
            Property1 = s.P1;
            Property2 = s.P2;
            Property3 = s.P3;
            Property4 = s.P4;
        };
        userSetting.Add(o);
    }
    Properties.Settings.Default.SettingName = userSetting;
}

现在,提取它的代码是这样的:

public void RestoreInfo()
{
    ArrayList setting = Properties.Settings.Default.SettingName;

    foreach (object o in setting)
    {
        MyObject data = (MyObject)o;
        // Do something with the data, like load it in a ListView
    }
}

我还确保使用 [global::System.Configuration.SettingsSerializeAs(global::System.Configuration.SettingsSerializeAs.Binary)] 装饰 Settings.Designer.cs 文件,如下所示:

    [global::System.Configuration.UserScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Configuration.SettingsSerializeAs(global::System.Configuration.SettingsSerializeAs.Binary)]
    public global::System.Collections.ArrayList SettingName
    {
        get {
            return ((global::System.Collections.ArrayList)(this["SettingName"]));
        }
        set {
            this["SettingName"] = value;
        }
    }

现在,信息会随机消失。我可以调试它并看到Properties.Settings.Default 正在为SettingName 返回一个空的ArrayList。我真的宁愿不使用 ArrayList,但我没有看到以这种方式存储通用集合的方法。

我即将放弃并自己使用纯 XML 保存这些信息。我只是想验证我确实将这一点 .NET 基础设施推得太远了。我说的对吗?

【问题讨论】:

    标签: c# .net winforms settings


    【解决方案1】:

    从您的示例中,我看不出您尝试做什么有任何不正确之处。我认为您描述的问题的根源可能是您的程序集版本更改?用户设置不会自动神奇地升级自己(至少我无法让他们升级)。

    我能理解你的困境,几个月前我就经历过。我编写了一个 UserSettings 类,该类在命名组标题下提供标准名称/值对集合 (KeyValueConfigurationElement),如下所示:

    <configSections>
      <section name="userSettings" type="CSharpTest.Net.AppConfig.UserSettingsSection, CSharpTest.Net.Library"/>
    </configSections>
    <userSettings>
      <add key="a" value="b"/>
      <sections>
        <section name="c">
          <add key="a" value="y"/>
        </section>
      </sections>
    </userSettings>
    

    无论如何,看看这是否满足您的需求,或者提供一些关于实施自定义 ConfigurationSection 以允许您需要的洞察力。

    哦,是的,代码在这里:

    http://csharptest.net/browse/src/Library/AppConfig

    【讨论】:

    • 很遗憾,程序集版本并没有改变,并且在新版本出来时已经在升级设置。
    【解决方案2】:

    在用户范围内使用设置功能时,设置将保存到当前登录用户的应用程序数据(Vista/7 中的 AppData)文件夹中。因此,如果 UserA 登录,使用您的应用程序,然后 UserB 登录,他将不会加载 UserA 的设置,他将拥有自己的设置。

    在您要完成的工作中,我建议使用XmlSerializer 类来序列化对象列表。使用很简单:

    序列化:

    ArrayList list = new ArrayList();
    XmlSerializer s = new XmlSerializer(typeof(ArrayList));
    using (FileStream fs = new FileStream(@"C:\path\to\settings.xml", FileMode.OpenOrCreate))
    {
        s.Serialize(fs, list);
    }
    

    反序列化:

    ArrayList list;
    XmlSerializer s = new XmlSerializer(typeof(ArrayList));
    using (FileStream fs = new FileStream(@"C:\path\to\settings.xml", FileMode.Open))
    {
        list = (ArrayList)s.Deserialize(fs);
    }
    

    【讨论】:

    • 这里只有一个用户,所以这个想法已经过时了。我很可能最终会使用手动序列化和反序列化。
    【解决方案3】:

    我找不到为什么这些设置会消失的答案,因为我不断发生这种情况,我最终将复杂的设置集单独存储在一个 XML 文件中,自己手动序列化和反序列化它们。

    【讨论】:

      【解决方案4】:

      在设置设计器类中使用 SettingsSerializeAs 二进制属性时,我有过非常相似的经历。它在测试中工作,但一段时间后它无法恢复属性值。

      在我的情况下,通过设计器对设置进行了后续添加。源代码管理历史显示 SettingsSerializeAs 属性已在我不知情的情况下从 Settings.Designer.cs 中删除。

      我添加了以下代码来检查属性是否被意外丢失,它相当于 RestoreInfo() 方法。

      #if(DEBUG)
                      //Verify that the Property has the required attribute for Binary serialization.
                      System.Reflection.PropertyInfo binarySerializeProperty = Properties.Settings.Default.GetType().GetProperty("SettingName");
                      object[] customAttributes = binarySerializeProperty.GetCustomAttributes(typeof(System.Configuration.SettingsSerializeAsAttribute), false);
                      if (customAttributes.Length != 1)
                      {
                          throw new ApplicationException("SettingsSerializeAsAttribute required for SettingName property");
                      }
      #endif
      

      此外,仅因为您的示例中缺少它,请不要忘记调用 Save。调用 SaveInfo() 后说。

      Properties.Settings.Default.Save();
      

      【讨论】:

      • 我很清楚你的问题是什么。每当您使用 GUI 修改设置配置时,设计器都会输出一个 ENTIRELY 新文件,覆盖您所做的所有自定义更改。是的,我知道,顶部有一个警告,不要自己进行更改,但我的意思是,来吧。 Visual Studio 团队没有考虑到给我一个复选框来切换它!哎,好郁闷。直到今天,我仍然有 一个 受 .NET 困扰的用户随机丢弃他的数据。我现在正在转向我可以读写的 XML,而不是依赖于 .NET。
      • @jasonh 该类是部分的。如果您在设置设计器中单击“查看代码”,您将获得一个 Settings.cs 文件(除了 Settings.Designer.cs),您可以在其中进行持久更改。
      • @Medinoc:除了,那些持久性更改不/不能包括属性本身的声明,其中将应用[SettingsSerializeAs]。您对如何使用partial 类文件来持续强制该设置/属性有什么建议吗?
      • 您无法更改现有属性,但您至少可以在ProjectName.settings 文件中添加自己的设置。使用正确的属性,它们将由设置引擎处理。
      猜你喜欢
      • 2011-04-07
      • 2013-03-28
      • 1970-01-01
      • 2011-01-14
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 2010-12-05
      相关资源
      最近更新 更多