Cách lưu mảng int [] trong Cài đặt ứng dụng


93

Tôi đang tạo một ứng dụng Windows Forms đơn giản bằng C # express 2008. Tôi là một nhà phát triển C ++ có kinh nghiệm, nhưng tôi còn khá mới mẻ với C # và .NET.

Tôi hiện đang lưu trữ một số cài đặt ứng dụng đơn giản của mình bằng trình thiết kế cài đặt và mã như sau:

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

Bây giờ tôi muốn lưu trữ một mảng ints ( int[]), hoặc có thể là một Danh sách các int ( List< int >), như một cài đặt. Tuy nhiên, tôi không thể tìm ra cách làm điều này. Tôi đã tìm kiếm tài liệu, stackoverflow và google, và tôi không thể tìm thấy lời giải thích hợp lý về cách thực hiện việc này.

Linh cảm của tôi dựa trên các ví dụ thưa thớt mà tôi đã tìm thấy là tôi phải tạo một lớp có thể tuần tự hóa bao bọc mảng hoặc Danh sách của tôi và sau đó tôi sẽ có thể sử dụng Loại đó trong trình thiết kế cài đặt. Tuy nhiên, tôi không chắc chắn chính xác cách thực hiện điều này.

Câu trả lời:


136

Ngoài ra còn có một giải pháp khác - yêu cầu chỉnh sửa thủ công một chút đối với tệp cài đặt, nhưng sau đó hoạt động tốt trong môi trường VS và trong mã. Và không yêu cầu chức năng bổ sung hoặc trình bao bọc.

Vấn đề là VS cho phép int[]loại tuần tự hóa theo mặc định trong tệp cài đặt - nó không cho phép bạn chọn nó theo mặc định. Vì vậy, hãy tạo một cài đặt với tên mong muốn (ví dụ: SomeTestSetting) và đặt nó ở bất kỳ loại nào (ví dụ: stringtheo mặc định). Lưu các thay đổi.

Bây giờ, hãy chuyển đến thư mục dự án của bạn và mở tệp "Properties \ Settings.settings" bằng trình soạn thảo văn bản (ví dụ: Notepad) Hoặc bạn có thể mở nó trong VS bằng cách nhấp chuột phải vào Solution Explorer trên "-> Thuộc tính -> Settings.settings ", chọn" Open With ... "và sau đó chọn" XML Editor "hoặc" Source Code (Text) Editor ". Trong cài đặt xml đã mở, hãy tìm cài đặt của bạn (nó sẽ giống như thế này):

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

Thay đổi tham số "Loại" từ System.Stringthành System.Int32[]. Bây giờ phần này sẽ giống như sau:

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

Bây giờ hãy lưu các thay đổi và mở lại cài đặt dự án - voilà! - Chúng tôi có cài đặt SomeTestSetting với loại System.Int32[]có thể được truy cập và chỉnh sửa thông qua VS Settings Designer (các giá trị cũng vậy), cũng như trong mã.


5
Tuyệt vời. Để nhập nội dung nào đó vào cài đặt bằng trình chỉnh sửa trong Visual Studio, bạn nên dán một cái gì đó như thế này, đây là cho một mảng chuỗi, đó là những gì tôi cần <? Xml version = "1.0" encoding = "utf-16"?> <ArrayOfString xmlns: xsi = " w3.org/2001/XMLSchema-instance " xmlns: xsd = " w3.org/2001/XMLSchema "> <string> String1 </string> <string> String2 </string> </ArrayOfString>
Karsten,

9
+1 .. không hiểu tại sao câu trả lời này không được chấp nhận .. không yêu cầu mã bổ sung (chỉ cần sửa đổi một dòng của xml hiện có) và bạn nhận được sự an toàn về loại và hỗ trợ đầy đủ so với nhà thiết kế!
Chris

1
Chris, cảm ơn :) Vấn đề là, tôi đã thêm câu trả lời của mình sau đó nhiều hơn câu trả lời được chấp nhận ban đầu (thực tế là khoảng một năm sau :)). Tuy nhiên, chỉ cần chia sẻ kinh nghiệm :)
Jen-Ari

6
Đối với bất kỳ ai tò mò, cú pháp tệp cấu hình XML cho int[]sẽ trông giống như thế này (ngoại trừ bản in đẹp):<setting name="SomeTestSetting" serializeAs="String"><value><ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><int>1</int><int>2</int><int>3</int></ArrayOfInt></value></setting>
aaaantoine 12/02/15

1
Đồng ý, đây là một câu trả lời tốt hơn, vì vậy tôi đã thay đổi dấu hiệu.
sideinderguy

40

để lưu trữ:

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

để tạo lại:

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

Chỉnh sửa: Đề xuất Abel!


Ok, như vậy có vẻ như bạn đang tuần tự hóa dữ liệu theo cách thủ công thành một chuỗi và ngược lại. Tôi đoán điều này sẽ hoạt động, tôi chỉ có thể lưu trữ dữ liệu dưới dạng cài đặt chuỗi. Tôi đã nghĩ đến việc làm một cái gì đó như thế này, nhưng tôi đang tìm kiếm một cái gì đó "sạch" hơn hoặc "tiêu chuẩn" hơn hoặc chỉ hơn .NET'ish. Tôi sẽ ghi nhớ điều này, nếu không có gì tốt hơn sẽ phát triển. Cảm ơn.
sideinderguy

Xin chào, tôi sẽ đi với đại lộ của McKay! (phần cấu hình / nhóm phần)
Mike Gleason jr Couturier

Tôi sẽ đi với điều này vì nó đơn giản. Cảm ơn tất cả các ý kiến ​​của mọi người, tôi chắc chắn rằng họ sẽ giúp đỡ trong quá trình thực hiện
sideinderguy

2
Lưu ý: Bạn sẽ cần phải System.Linqthêm vào việc sử dụng / nhập khẩu để thủ thuật trên hoạt động.
Sean Hanley

11

Có một cách khác để đạt được kết quả này là cách sử dụng gọn gàng hơn rất nhiều nhưng yêu cầu nhiều mã hơn. Việc triển khai công cụ chuyển đổi loại và loại tùy chỉnh của tôi có thể thực hiện được mã sau:

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

Để đạt được điều này, bạn cần một loại có bộ chuyển đổi loại cho phép chuyển đổi sang và từ chuỗi. Bạn thực hiện việc này bằng cách trang trí loại bằng TypeConverterAttribute:

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

Sau đó, triển khai trình chuyển đổi kiểu này như một dẫn xuất của 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);
    }
}

Bằng cách cung cấp một số phương thức tiện lợi trên lớp MyNumberArray, sau đó chúng ta có thể gán vào và từ List một cách an toàn, lớp hoàn chỉnh sẽ trông giống như sau:

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

Cuối cùng, để sử dụng điều này trong cài đặt, bạn thêm các lớp trên vào một hợp ngữ và biên dịch. Trong trình soạn thảo Settings.settings, bạn chỉ cần nhấp vào tùy chọn "Duyệt qua" và chọn lớp MyNumberArray và bạn bắt đầu.

Một lần nữa, đây là nhiều mã hơn; tuy nhiên, nó có thể được áp dụng cho các kiểu dữ liệu phức tạp hơn nhiều so với một mảng đơn giản.


Cảm ơn, điều này có vẻ thú vị. Tôi sẽ thử khi có cơ hội.
sideinderguy

3

Chỉ định cài đặt dưới dạng System.Collections.ArrayList và sau đó:

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

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

2

Một giải pháp đơn giản là đặt giá trị mặc định của một cài đặt thành null trong thuộc tính, nhưng trong hàm khởi tạo, hãy kiểm tra xem thuộc tính có là null hay không và nếu có thì hãy đặt nó thành giá trị mặc định thực tế của nó. Vì vậy, nếu bạn muốn có một mảng 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;
        }
    }
}

Nó cảm thấy hơi khó hiểu, nhưng nó sạch sẽ và hoạt động như mong muốn vì các thuộc tính được khởi tạo thành cài đặt cuối cùng (hoặc mặc định) của chúng trước khi hàm tạo được gọi.


2
Trình thiết kế tệp cài đặt ứng dụng tự động tạo mã và do đó, một thay đổi như thế này sẽ bị ghi đè bất cứ lúc nào bất kỳ ai sử dụng trình thiết kế, thậm chí là vô tình.
Carl G

1

Đã qua sử dụng System.Object.

Thí dụ:

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

Trích xuất:

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

1
Tôi đã thử sử dụng System.Object, nhưng cài đặt không tồn tại giữa các phiên. (Có đó là một phát hành xây dựng, độc lập cài đặt, bất cứ điều gì bạn muốn gọi nó, tôi đã không gỡ lỗi bằng cách sử dụng IDE)
Emanuel Vintilă

0

Tôi nghĩ rằng bạn đã đúng khi sắp xếp các cài đặt của mình. Xem câu trả lời của tôi cho câu hỏi này để biết mẫu:

Kỹ thuật chia sẻ cấu hình giữa hai ứng dụng?

Bạn sẽ có một thuộc tính là một mảng, như thế này:

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

0

Thực hiện một số hàm chuyển đổi một mảng int trong một chuỗi, nhưng giữa mỗi hàm đặt một ký tự như "" (dấu cách).

Vì vậy, nếu mảng là {1,34,546,56} thì chuỗi sẽ là "1 34 645 56"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.