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

发布于 2024-12-11 11:52:19 字数 571 浏览 1 评论 0原文

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

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

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

现在我想存储一个整数数组( int[] ),或者可能是一个列表ints (List),作为设置。但是,我不知道该怎么做。我搜索了文档、stackoverflow 和 google,但找不到关于如何执行此操作的合理解释。

根据我发现的稀疏示例,我的预感是我必须创建一个可序列化的类来包装我的数组或列表,然后我将能够在设置设计器中使用该类型。但是,我不确定具体该怎么做。

I'm creating a simple windows Forms application using C# express 2008. I'm an experienced C++ developer, but I am pretty much brand new to C# and .NET.

I'm currently storing some of my simple application settings using the settings designer and code like this:

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

Now I'd like to store either an array of ints ( int[] ), or possibly a List of ints ( List< int > ), as a setting. However, I can't figure out how to do this. I've searched the documentation, stackoverflow, and google, and I cannot find a decent explanation of how to do this.

My hunch based on the sparse examples I've found is that I have to create a class that is serializable that wraps my array or List, and then I will be able to use that Type in the settings designer. However, I'm not sure exactly how to do this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

乙白 2024-12-18 11:52:19

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

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

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

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

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

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

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

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.

空气里的味道 2024-12-18 11:52:19

存储:

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

重新创建:

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

编辑:阿贝尔建议!

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!

蝶…霜飞 2024-12-18 11:52:19

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

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

所示:

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

通过在 MyNumberArray 类上提供一些方便的方法,我们可以安全地在 List 之间进行赋值,完整的类将如下 ,要在设置中使用它,请将上述类添加到程序集中并编译。在您的 Settings.settings 编辑器中,您只需单击“浏览”选项并选择 MyNumberArray 类即可。

同样,这需要更多的代码;但是,它可以应用于比简单数组更复杂的数据类型。

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.

隐诗 2024-12-18 11:52:19

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

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

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

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));
梨涡少年 2024-12-18 11:52:19

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

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,但它干净并且可以按需要工作,因为属性在调用构造函数之前被初始化为其最后(或默认)设置。

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.

慵挽 2024-12-18 11:52:19

使用System.Object

示例:

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

摘录:

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

Used System.Object.

Example:

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

Extract:

arBytes = (byte[])Properties.Settings.Default.KeyObject;
呆橘 2024-12-18 11:52:19

我认为你关于序列化你的设置是正确的。请参阅我对此问题的回答以获取示例:

技术在两个应用程序之间共享配置?

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

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

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; }
孤云独去闲 2024-12-18 11:52:19

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

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

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"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文