如何在应用程序设置中存储int []数组

时间:2009-11-19 21:14:13

标签: c# winforms arrays settings

我正在使用C#express 2008创建一个简单的Windows窗体应用程序。我是一位经验丰富的C ++开发人员,但我对C#和.NET几乎全新。

我目前正在使用设置设计器和代码存储一些简单的应用程序设置:

// Store setting  
Properties.Settings.Default.TargetLocation = txtLocation.Text;  
...  
// Restore setting  
txtLocation.Text = Properties.Settings.Default.TargetLocation;  

现在我想要存储一个int数组(int[]),或者可能存储一个int(List< int >)列表作为设置。但是,我无法弄清楚如何做到这一点。我搜索了文档,stackoverflow和谷歌,我找不到如何做到这一点的正确解释。

基于我发现的稀疏示例,我的预感是我必须创建一个可序列化的类来包装我的数组或List,然后我将能够在设置设计器中使用该类型。但是,我不确定如何做到这一点。

8 个答案:

答案 0 :(得分:128)

还有另一个解决方案 - 需要对设置文件进行一些手动编辑,但之后在VS环境和代码中工作正常。并且不需要额外的功能或包装。

问题是,VS允许在设置文件中默认序列化int[]类型 - 它默认情况下不允许您选择它。 因此,创建一个具有所需名称的设置(例如SomeTestSetting)并使其成为任何类型(默认情况下为string)。 保存更改。

现在转到项目文件夹并使用文本编辑器打开“Properties \ Settings.settings”文件(例如,记事本)或者您可以通过右键单击解决方案资源管理器中的“ - &gt;属性 - 在VS中打开它”。 &gt; Settings.settings“,选择”打开方式...“,然后选择”XML编辑器“或”源代码(文本)编辑器“。 在打开的xml设置中找到您的设置(它将如下所示):

<Setting Name="SomeTestSetting" Type="System.String" Scope="User">
  <Value Profile="(Default)" />
</Setting>

将“类型”参数从System.String更改为System.Int32[]。现在这部分将如下所示:

<Setting Name="SomeTestSetting" Type="System.Int32[]" Scope="User">
  <Value Profile="(Default)" />
</Setting>

现在保存更改并重新打开项目设置 - 瞧! - 我们设置SomeTestSetting类型System.Int32[],可以通过VS设置设计器(也是值)以及代码访问和编辑。

答案 1 :(得分:40)

存储:

string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());

重新创建:

int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();

编辑:阿贝尔的建议!

答案 2 :(得分:11)

还有另一种方法可以实现这种结果,使用起来更清洁但需要更多代码。我实现了自定义类型和类型转换器,可以使用以下代码:

List<int> array = Settings.Default.Testing;
array.Add(new Random().Next(10000));
Settings.Default.Testing = array;
Settings.Default.Save();

要实现这一点,您需要一个带有类型转换器的类型,允许转换为字符串和从字符串转换。您可以通过使用TypeConverterAttribute:

修饰类型来完成此操作
[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray ...

然后将此类型转换器实现为TypeConverter的派生:

class MyNumberArrayConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override bool CanConvertFrom(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override object ConvertTo(ITypeDescriptorContext ctx, CultureInfo ci, object value, Type type)
    {
        MyNumberArray arr = value as MyNumberArray;
        StringBuilder sb = new StringBuilder();
        foreach (int i in arr)
            sb.Append(i).Append(',');
        return sb.ToString(0, Math.Max(0, sb.Length - 1));
    }

    public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
    {
        List<int> arr = new List<int>();
        if (data != null)
        {
            foreach (string txt in data.ToString().Split(','))
                arr.Add(int.Parse(txt));
        }
        return new MyNumberArray(arr);
    }
}

通过在MyNumberArray类上提供一些便捷方法,我们可以安全地从List中分配,完整的类看起来像:

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray : IEnumerable<int>
{
    List<int> _values;

    public MyNumberArray() { _values = new List<int>(); }
    public MyNumberArray(IEnumerable<int> values) { _values = new List<int>(values); }

    public static implicit operator List<int>(MyNumberArray arr)
    { return new List<int>(arr._values); }
    public static implicit operator MyNumberArray(List<int> values)
    { return new MyNumberArray(values); }

    public IEnumerator<int> GetEnumerator()
    { return _values.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator()
    { return ((IEnumerable)_values).GetEnumerator(); }
}

最后,要在设置中使用它,请将上述类添加到程序集并进行编译。在Settings.settings编辑器中,只需单击“浏览”选项并选择MyNumberArray类即可。

这又是一个代码;但是,它可以应用于比简单数组更复杂的数据类型。

答案 3 :(得分:3)

将设置指定为System.Collections.ArrayList,然后:

Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 });

int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));

答案 4 :(得分:2)

一个简单的解决方案是在属性中将设置的默认值设置为null,但在构造函数中检查属性是否为null,如果是,则将其设置为其实际默认值。所以,如果你想要一组int:

public class ApplicationSettings : ApplicationSettingsBase
{
    public ApplicationSettings()
    {
        if( this.SomeIntArray == null )
            this.SomeIntArray = new int[] {1,2,3,4,5,6};
    }

    [UserScopedSetting()]
    [DefaultSettingValue("")]
    public int[] SomeIntArray
    {
        get
        {
            return (int[])this["SomeIntArray"];
        }
        set
        {
            this["SomeIntArray"] = (int[])value;
        }
    }
}

感觉有点hacky,但它干净并且按照需要工作,因为在调用构造函数之前,属性被初始化为它们的最后(或默认)设置。

答案 5 :(得分:1)

使用System.Object

示例:

byte[] arBytes = new byte[] { 10, 20, 30 };
Properties.Settings.Default.KeyObject = arBytes;

提取物:

arBytes = (byte[])Properties.Settings.Default.KeyObject;

答案 6 :(得分:0)

我认为您对序列化设置是正确的。有关示例,请参阅我对此问题的回答:

Techniques for sharing a config between two apps?

你将拥有一个属性数组,如下所示:

/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int [] Numbers { get; set; }

答案 7 :(得分:0)

创建一些在字符串中转换int数组的函数,但在每个函数之间放置一个像“”(空格)这样的字符。

因此,如果数组为{1,34,546,56},则字符串为“1 34 645 56”