İnt [] dizisi uygulama ayarlarında nasıl saklanır


93

C # express 2008 kullanarak basit bir Windows Forms uygulaması oluşturuyorum. Deneyimli bir C ++ geliştiricisiyim, ancak C # ve .NET konusunda oldukça yeniyim.

Şu anda ayar tasarımcısını ve aşağıdaki gibi kodu kullanarak bazı basit uygulama ayarlarımı saklıyorum:

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

Şimdi bir ayar olarak ya bir dizi ints ( int[]) ya da muhtemelen bir İnts Listesi ( ) depolamak istiyorum List< int >. Ancak bunu nasıl yapacağımı çözemiyorum. Belgeleri, stackoverflow'u ve google'ı araştırdım ve bunun nasıl yapılacağına dair iyi bir açıklama bulamıyorum.

Bulduğum seyrek örneklere dayanan önsezim, dizimi veya Listemi saran serileştirilebilir bir sınıf oluşturmam gerektiğidir ve daha sonra bu Türü ayar tasarımcısında kullanabileceğimdir. Ancak bunu nasıl yapacağımdan tam olarak emin değilim.

Yanıtlar:


137

Başka bir çözüm daha var - ayarlar dosyasının biraz manuel olarak düzenlenmesini gerektirir, ancak daha sonra VS ortamında ve kodda iyi çalışır. Ve hiçbir ek işlev veya sarmalayıcı gerektirmez.

Mesele şu ki, VS, int[]varsayılan olarak ayarlar dosyasında türü serileştirmeye izin veriyor - sadece varsayılan olarak seçmenize izin vermiyor. Bu nedenle, istenen adla bir ayar oluşturun (örn. SomeTestSetting) ve bunu herhangi bir türde yapın (örn string. Varsayılan olarak). Değişiklikleri kaydedin.

Şimdi proje klasörünüze gidin ve metin düzenleyiciyle "Properties \ Settings.settings" dosyasını açın (örneğin, Notepad) Veya "-> Properties -> Settings.settings'deki Solution Explorer'da sağ tıklayarak VS'de açabilirsiniz. "," Birlikte Aç ... "öğesini seçin ve ardından" XML Düzenleyici "veya" Kaynak Kodu (Metin) Düzenleyicisi "ni seçin. Açılan xml ayarlarında ayarınızı bulun (şöyle görünecektir):

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

"Tür" parametresini olarak System.Stringdeğiştirin System.Int32[]. Şimdi bu bölüm şöyle görünecek:

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

Şimdi değişiklikleri kaydedin ve proje ayarlarını yeniden açın - voilà! - System.Int32[]VS Ayar Tasarımcısı (değerler de) aracılığıyla ve kodda erişilebilen ve düzenlenebilen tipli SomeTestSetting ayarına sahibiz .


5
Harika. Visual Studio'da düzenleyiciyi kullanarak ayara bir şey girmek için, buna benzer bir şey yapıştırmalısınız, bu bir dize dizisi içindir, ihtiyacım olan buydu <? Xml version = "1.0" encoding = "utf-16"?> <ArrayOfString xmlns: xsi = " w3.org/2001/XMLSchema-instance " xmlns: xsd = " w3.org/2001/XMLSchema "> <string> Dize1 </string> <string> Dize2 </string> </ArrayOfString>
Karsten

9
+1 .. yanıtın neden kabul edilmediğini anlamayın .. ekstra kod gerekmez (sadece mevcut xml'nin bir satırını değiştirin) ve tasarımcı desteğine karşı tip güvenliği ve tam alırsınız!
Chris

1
Chris, teşekkürler :) Mesele şu ki, cevabımı daha sonra ekledim, ilk kabul edilen cevabı (yaklaşık bir yıl sonra, aslında :)). Yine de deneyimi paylaşıyorum :)
Jen-Ari

6
Merak int[]<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>
edenler

1
Kabul edildi, bu daha iyi bir cevap, bu yüzden işareti değiştirdim.
sidewinderguy

42

depolamak:

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

yeniden oluşturmak için:

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

Düzenleme: Abel önerisi!


Tamam, bu, verileri manuel olarak bir dizeye serileştiriyorsunuz gibi görünüyor ve bunun tersi de geçerli. Sanırım bu işe yarardı, verileri bir dizge ayarı olarak saklayabilirdim. Bunun gibi bir şey yapmayı düşündüm, ama daha "temiz" veya "standart" veya daha .NET'ish bir şey arıyordum. Daha iyi bir şey yetişmezse, bunu aklımda tutacağım. Teşekkürler.
sidewinderguy

Merhaba, o zaman McKay'in caddesine giderdim! (yapılandırma bölümü / bölüm grubu)
Mike Gleason jr Couturier

Bununla devam edeceğim çünkü basit. Tüm fikirler için teşekkürler herkese, eminim ki ileride yardımcı olacaklardır.
sidewinderguy

2
Not: System.LinqYukarıdaki numaranın çalışması için kullanımlarınıza / içe aktarmalarınıza eklemeniz gerekir .
Sean Hanley

11

Bu sonucu elde etmenin kullanım açısından çok daha temiz olan ancak daha fazla kod gerektiren başka bir yolu daha var. Özel bir tür ve tür dönüştürücü uygulamam aşağıdaki kod mümkündür:

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

Bunu başarmak için, dizelere ve dizelerden dönüşüme izin veren bir tür dönüştürücüye sahip bir türe ihtiyacınız vardır. TypeConverterAttribute ile türü dekore ederek bunu yaparsınız:

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

Ardından, bu tür dönüştürücüyü TypeConverter'ın bir türevi olarak uygulamak:

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 sınıfında bazı kolaylık yöntemleri sağlayarak, daha sonra güvenli bir şekilde List'e ve Listeden atayabiliriz, tüm sınıf şöyle görünür:

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

Son olarak, bunu ayarlarda kullanmak için yukarıdaki sınıfları bir derleme ve derlemeye eklersiniz. Settings.settings düzenleyicinizde "Browse" seçeneğini tıklayıp MyNumberArray sınıfını seçip başlayın.

Yine bu çok daha fazla koddur; ancak, basit bir diziden çok daha karmaşık veri türlerine uygulanabilir.


Teşekkürler, bu ilginç görünüyor. Şansım olduğunda deneyeceğim.
sidewinderguy

3

Ayarı System.Collections.ArrayList olarak belirtin ve ardından:

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

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

2

Basit bir çözüm, bir ayarın varsayılan değerini özellikte null olarak ayarlamaktır, ancak yapıcıda özelliğin null olup olmadığını kontrol edin ve öyleyse gerçek varsayılan değerine ayarlayın. Öyleyse, bir dizi dizi istiyorsanız:

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

Bir tür hilekar gibi hissediyor, ancak temiz ve istendiği gibi çalışıyor çünkü özellikler, kurucu çağrılmadan önce son (veya varsayılan) ayarlarına başlatılıyor.


2
Uygulama ayar dosyalarının tasarımcısı kodu otomatik olarak oluşturur ve bu nedenle böyle bir değişiklik, herhangi biri tasarımcıyı her kullandığında, yanlışlıkla bile olsa, üzerine yazılır.
Carl G

1

Kullanılmış System.Object .

Misal:

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

Ayıkla:

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

1
System.Object kullanmayı denedim, ancak ayarlar oturum arasında kalmıyordu. (Evet, bir sürüm yapısıydı, bağımsız kurulum, ne derseniz deyin,
IDE'yi

0

Ayarlarınızı seri hale getirme konusunda haklı olduğunuzu düşünüyorum. Bir örnek için bu soruya verdiğim cevaba bakın:

İki uygulama arasında yapılandırma paylaşma teknikleri?

Aşağıdaki gibi dizi olan bir özelliğe sahip olursunuz:

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

0

Bir dizedeki bir int dizisini dönüştüren bazı işlevler yapın, ancak her birinin arasına "" (boşluk) gibi bir karakter koyun.

Yani dizi {1,34,546,56} ise, dize "1 34 645 56" olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.