Bagaimana cara menyimpan int [] array dalam pengaturan aplikasi

93

Saya membuat aplikasi Windows Forms sederhana menggunakan C # express 2008. Saya adalah pengembang C ++ berpengalaman, tetapi saya cukup baru mengenal C # dan .NET.

Saat ini saya menyimpan beberapa pengaturan aplikasi sederhana saya menggunakan desainer pengaturan dan kode seperti ini:

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

Sekarang saya ingin menyimpan array ints ( int[]), atau mungkin List of ints ( List< int >), sebagai pengaturan. Namun, saya tidak tahu bagaimana melakukan ini. Saya telah mencari dokumentasi, stackoverflow, dan google, dan saya tidak dapat menemukan penjelasan yang layak tentang bagaimana melakukan ini.

Firasat saya berdasarkan contoh jarang yang saya temukan adalah bahwa saya harus membuat kelas yang dapat diserialisasi yang membungkus array atau Daftar saya, dan kemudian saya akan dapat menggunakan Jenis itu di desainer pengaturan. Namun, saya tidak yakin persis bagaimana melakukan ini.

sidewinderguy
sumber

Jawaban:

137

Ada juga solusi lain - memerlukan sedikit pengeditan manual dari file pengaturan, tetapi setelah itu berfungsi dengan baik di lingkungan VS dan dalam kode. Dan tidak membutuhkan fungsi atau pembungkus tambahan.

Masalahnya, VS memungkinkan untuk membuat int[]jenis serial secara default di file pengaturan - itu tidak memungkinkan Anda untuk memilihnya secara default. Jadi, buat pengaturan dengan nama yang diinginkan (mis. SomeTestSetting) dan buat jenis apa pun (mis. Secara stringdefault). Simpan perubahannya.

Sekarang pergi ke folder proyek Anda dan buka file "Properties \ Settings.settings" dengan editor teks (Notepad, misalnya) Atau Anda dapat membukanya di VS dengan mengklik kanan di Solution Explorer pada "-> Properties -> Settings.settings ", pilih" Buka Dengan ... "lalu pilih" Editor XML "atau" Editor Kode Sumber (Teks) ". Di pengaturan xml yang terbuka, temukan pengaturan Anda (akan terlihat seperti ini):

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

Ubah parameter "Type" dari System.Stringmenjadi System.Int32[]. Sekarang bagian ini akan terlihat seperti ini:

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

Sekarang simpan perubahan dan buka kembali pengaturan proyek - voila! - Kami memiliki pengaturan SomeTestSetting dengan tipe System.Int32[]yang dapat diakses dan diedit melalui VS Settings Designer (nilai juga), serta dalam kode.

Jen-Ari
sumber
5
Hebat. Untuk memasukkan sesuatu ke dalam pengaturan menggunakan editor di Visual Studio, Anda harus menempelkan sesuatu seperti ini, ini untuk larik string, yang saya butuhkan <? 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 .. tidak mengerti mengapa ini tidak diterima jawaban .. tidak diperlukan kode tambahan (cukup modifikasi satu baris xml yang ada) dan Anda mendapatkan keamanan tipe dan dukungan penuh vs desainer!
Chris
1
Chris, terima kasih :) Masalahnya, saya telah menambahkan jawaban saya lebih lama daripada jawaban yang awalnya diterima (sekitar setahun kemudian, sebenarnya :)). Hanya berbagi pengalaman :)
Jen-Ari
6
Bagi siapa pun yang penasaran, sintaks XML file konfigurasi untuk int[]akan terlihat seperti ini (kecuali cukup tercetak):<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
1
Setuju, ini adalah jawaban yang lebih baik, jadi saya mengubah tandanya.
sidewinderguy
40

menyimpan:

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

untuk membuat ulang:

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

Edit: Saran Abel!

Mike Gleason jr Couturier
sumber
Oke, jadi ini terlihat seperti Anda membuat serialisasi data secara manual menjadi string, dan sebaliknya. Saya kira ini akan berhasil, saya hanya bisa menyimpan data sebagai pengaturan string. Saya berpikir untuk melakukan sesuatu seperti ini, tetapi saya mencari sesuatu yang lebih "bersih" atau "standar" atau lebih .NET'ish. Saya akan mengingat ini, jika tidak ada yang lebih baik. Terima kasih.
sidewinderguy
Halo, saya akan memilih jalan McKay! (bagian konfigurasi / grup bagian)
Mike Gleason jr Couturier
Saya akan memilih ini karena sederhana. Terima kasih untuk semua ide semuanya, saya yakin mereka akan membantu di masa mendatang.
sidewinderguy
2
Catatan: Anda harus System.Linqmenambahkan penggunaan / impor Anda agar trik di atas berfungsi.
Sean Hanley
11

Ada satu cara lain untuk mencapai hasil ini yang jauh lebih bersih dalam penggunaan tetapi membutuhkan lebih banyak kode. Saya menerapkan konverter tipe dan tipe kustom, kode berikut dimungkinkan:

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

Untuk mencapai ini, Anda memerlukan tipe dengan konverter tipe yang memungkinkan konversi ke dan dari string. Anda melakukan ini dengan mendekorasi tipe dengan TypeConverterAttribute:

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

Kemudian mengimplementasikan konverter tipe ini sebagai turunan dari 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);
    }
}

Dengan menyediakan beberapa metode praktis pada kelas MyNumberArray, kita dapat menetapkan dengan aman ke dan dari List, kelas lengkap akan terlihat seperti:

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

Terakhir, untuk menggunakan ini dalam pengaturan Anda menambahkan kelas di atas ke assembly dan kompilasi. Dalam editor Settings.settings Anda cukup mengklik opsi "Browse" dan memilih kelas MyNumberArray dan pergilah.

Sekali lagi ini lebih banyak kode; namun, ini dapat diterapkan pada jenis data yang jauh lebih rumit daripada larik sederhana.

csharptest.net
sumber
Terima kasih ini terlihat menarik. Saya akan mencobanya saat ada kesempatan.
sidewinderguy
3

Tentukan pengaturan sebagai System.Collections.ArrayList dan kemudian:

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

int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
João Angelo
sumber
2

Solusi sederhananya adalah menyetel nilai default dari suatu setelan ke null di properti, tetapi di konstruktor periksa apakah properti tersebut null dan jika demikian, setel ke nilai default aktualnya. Jadi, jika Anda menginginkan array 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;
        }
    }
}

Rasanya agak hacky, tetapi bersih dan berfungsi seperti yang diinginkan karena properti diinisialisasi ke pengaturan terakhir (atau default) sebelum konstruktor dipanggil.

Russell Bearden
sumber
2
Perancang untuk file pengaturan aplikasi membuat kode secara otomatis, dan perubahan seperti ini akan ditimpa setiap kali seseorang menggunakan perancang, bahkan secara tidak sengaja.
Carl G
1

Digunakan System.Object.

Contoh:

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

Ekstrak:

arBytes = (byte[])Properties.Settings.Default.KeyObject;
Slavia
sumber
1
Saya mencoba menggunakan System.Object, tetapi pengaturan tidak bertahan di antara sesi. (Ya, itu adalah build rilis, pemasangan mandiri, apa pun sebutannya, saya tidak melakukan debug menggunakan IDE)
Emanuel Vintilă
0

Saya pikir Anda benar tentang membuat serial pengaturan Anda. Lihat jawaban saya untuk pertanyaan ini untuk contoh:

Teknik berbagi konfigurasi antara dua aplikasi?

Anda akan memiliki properti berupa array, seperti ini:

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

Buat beberapa fungsi yang mengonversi larik int dalam sebuah string, tetapi di antara masing-masing, letakkan karakter seperti "" (spasi).

Jadi jika arraynya adalah {1,34,546,56} stringnya akan menjadi "1 34 645 56"

pengguna1452079
sumber