这是滥用设置功能吗?

时间:2009-10-06 22:29:14

标签: c# .net winforms settings

我一直在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.DefaultArrayList返回空SettingName。我真的不想使用ArrayList,但我没有看到以这种方式存储泛型集合的方法。

我即将放弃并使用纯XML保存此信息。我只是想验证我确实在推动.NET基础架构这么远。我是对的吗?

3 个答案:

答案 0 :(得分:1)

在Settings Designer类中使用SettingsSerializeAs二进制属性时,我有类似的经验。它在测试中起作用,但一段时间后它无法恢复属性值。

在我的情况下,随后通过设计师添加了设置。源代码控制历史记录显示在我不知情的情况下,Settings.SerializeAs属性已从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();

答案 1 :(得分:0)

从您的示例中我看不出有什么不正确的尝试。我认为您描述的问题的根源可能是您的汇编版本在变化?用户设置不会自动神奇地升级自己(至少我无法让他们自己升级)。

我很欣赏你的困境,几个月前我经历过这个。我编写了一个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 :(得分:0)

将“设置”功能与“用户”范围一起使用时,设置将保存到当前登录用户的“应用程序数据”(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);
}