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

我正在使用 C # Express 2008创建一个简单的 windows Forms 应用程序。我是一个经验丰富的 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 和 google,但是我找不到一个合适的解释来说明如何做到这一点。

基于我发现的稀疏示例,我的直觉是,我必须创建一个可序列化的类来包装我的数组或 List,然后我就可以在设置设计器中使用这个 Type。但是,我不知道该怎么做。

67515 次浏览

to store:

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

to re-create:

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

Edit: Abel suggestion!

I think you are right about serializing your settings. See my answer to this question for a sample:

Techniques for sharing a config between two apps?

You would have a property which is an array, like this:

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

Specify the setting as a System.Collections.ArrayList and then:

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


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

There is one other way to achieve this result that is a lot cleaner in usage but requires more code. My implementing a custom type and type converter the following code is possible:

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

To achieve this you need a type with a type converter that allows conversion to and from strings. You do this by decorating the type with the TypeConverterAttribute:

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray ...

Then implementing this type converter as a derivation of 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);
}
}

By providing some convenience methods on the MyNumberArray class we can then safely assign to and from List, the complete class would look something like:

[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(); }
}

Lastly, to use this in the settings you add the above classes to an assembly and compile. In your Settings.settings editor you simply click the "Browse" option and select the MyNumberArray class and off you go.

Again this is a lot more code; however, it can be applied to much more complicated types of data than a simple array.

There is also another solution - requires a bit of manual editing of the settings file, but afterwards works fine in VS environment and in the code. And requires no additional functions or wrappers.

The thing is, that VS allows to serialize int[] type by default in the settings file - it just doesn't allow you to select it by default. So, create a setting with desired name (e.g. SomeTestSetting) and make it of any type (e.g. string by default). Save the changes.

Now go to your project folder and open the "Properties\Settings.settings" file with text editor (Notepad, for example) Or you can open it in VS by right-clicking in Solution Explorer on " -> Properties -> Settings.settings", select "Open With..." and then choose either "XML Editor" or "Source Code (Text) Editor". In the opened xml settings find your setting (it will look like this):

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

Change the "Type" param from System.String to System.Int32[]. Now this section will look like this:

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

Now save changes and re-open project settings - voilà! - We have the setting SomeTestSetting with type System.Int32[] which can be accessed and edited through VS Settings Designer (values too), as well as in the code.

A simple solution is to set the default value of a setting to null in the property, but in the constructor check if the property is null and if so then set it to its actual default value. So if you wanted an array of ints:

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;
}
}
}

It feels kind of hacky, but its clean and works as desired since the properties are initialized to their last (or default) settings before the constructor is called.

Used System.Object.

Example:

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

Extract:

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

Make some functions that convert a int array in a string, but between each put a character like " " (space).

So if the array is { 1,34,546,56 } the string would be "1 34 645 56"