Come memorizzare l'array int [] nelle Impostazioni dell'applicazione


93

Sto creando una semplice applicazione Windows Forms utilizzando C # express 2008. Sono uno sviluppatore C ++ esperto, ma sono praticamente nuovo di zecca per C # e .NET.

Attualmente sto memorizzando alcune delle mie semplici impostazioni dell'applicazione utilizzando il designer delle impostazioni e il codice in questo modo:

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

Ora vorrei memorizzare o un array di int ( int[]), o forse un List of ints ( List< int >), come impostazione. Tuttavia, non riesco a capire come farlo. Ho cercato nella documentazione, nello stackoverflow e in Google e non riesco a trovare una spiegazione decente di come farlo.

La mia impressione basata sugli esempi sparsi che ho trovato è che devo creare una classe serializzabile che avvolge il mio array o elenco, e quindi sarò in grado di utilizzare quel tipo nel designer delle impostazioni. Tuttavia, non sono sicuro di come farlo.

Risposte:


136

C'è anche un'altra soluzione: richiede un po 'di modifica manuale del file delle impostazioni, ma in seguito funziona bene nell'ambiente VS e nel codice. E non richiede funzioni o wrapper aggiuntivi.

Il fatto è che VS consente di serializzare il int[]tipo per impostazione predefinita nel file delle impostazioni - semplicemente non ti consente di selezionarlo per impostazione predefinita. Quindi, crea un'impostazione con il nome desiderato (es. SomeTestSetting) e rendila di qualsiasi tipo (esstring per impostazione predefinita). Salva le modifiche.

Ora vai alla cartella del tuo progetto e apri il file "Proprietà \ Impostazioni.settings" con un editor di testo (Blocco note, ad esempio) Oppure puoi aprirlo in VS facendo clic con il tasto destro in Esplora soluzioni su "-> Proprietà -> Impostazioni.settings ", seleziona" Apri con ... "e quindi scegli" Editor XML "o" Editor del codice sorgente (testo) ". Nelle impostazioni xml aperte trova la tua impostazione (sarà simile a questa):

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

Modificare il parametro "Tipo" da System.Stringa System.Int32[]. Ora questa sezione sarà simile a questa:

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

Ora salva le modifiche e riapri le impostazioni del progetto - voilà! - Abbiamo l'impostazione SomeTestSetting con il tipo a System.Int32[]cui è possibile accedere e modificare tramite VS Settings Designer (anche i valori), nonché nel codice.


5
Eccezionale. Per inserire qualcosa nell'impostazione utilizzando l'editor in Visual Studio, dovresti incollare qualcosa di simile, questo è per un array di stringhe, che era quello che mi serviva <? 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 .. non capisco perché questa risposta non è stata accettata .. non è richiesto alcun codice aggiuntivo (basta modificare una riga di xml esistente) e ottieni la protezione dai tipi e il supporto completo rispetto al designer!
— Chris,

1
Chris, grazie :) Il fatto è che ho aggiunto la mia risposta molto più tardi rispetto alla risposta originariamente accettata (circa un anno dopo, in realtà :)). Tuttavia, condivido solo l'esperienza :)
— Jen-Ari

6
Per chiunque sia curioso, la sintassi XML del file di configurazione per int[]sarebbe simile a questa (tranne che piuttosto stampata):<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
D'accordo, questa è una risposta migliore, quindi ho cambiato il segno.
— sidewinderguy

40

immagazzinare:

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

per ricreare:

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

Modifica: suggerimento di Abele!


Ok, quindi sembra che tu stia serializzando i dati manualmente in una stringa e viceversa. Immagino che questo funzionerebbe, potrei semplicemente memorizzare i dati come un'impostazione di stringa. Ho pensato di fare qualcosa di simile, ma stavo cercando qualcosa di più "pulito" o "standard" o semplicemente più .NET'ish. Lo terrò a mente, se non dovesse emergere niente di meglio. Grazie.
— sidewinderguy

Ciao, allora andrei con McKay's Avenue! (sezione di configurazione / gruppo di sezioni)
— Mike Gleason jr Couturier

Vado con questo perché è semplice. Grazie per tutte le idee a tutti, sono sicuro che aiuteranno lungo la strada.
— sidewinderguy

2
Nota: dovrai aver System.Linqaggiunto ai tuoi usi / importazioni affinché il trucco di cui sopra funzioni.
— Sean Hanley,

11

C'è un altro modo per ottenere questo risultato che è molto più pulito nell'uso ma richiede più codice. La mia implementazione di un tipo personalizzato e convertitore di tipi è possibile il seguente codice:

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

Per ottenere ciò è necessario un tipo con un convertitore di tipi che consenta la conversione da e verso stringhe. Puoi farlo decorando il tipo con TypeConverterAttribute:

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

Quindi implementare questo convertitore di tipi come derivazione di 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);
    }
}

Fornendo alcuni metodi di convenienza sulla classe MyNumberArray che possiamo quindi assegnare in modo sicuro a e da List, la classe completa sarebbe simile a:

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

Infine, per usarlo nelle impostazioni, aggiungi le classi precedenti a un assembly e compila. Nel tuo editor Settings.settings fai semplicemente clic sull'opzione "Browse" e seleziona la classe MyNumberArray e il gioco è fatto.

Anche in questo caso è molto più codice; tuttavia, può essere applicato a tipi di dati molto più complicati rispetto a un semplice array.


Grazie, sembra interessante. Lo proverò quando ne avrò la possibilità.
— sidewinderguy

3

Specificare l'impostazione come System.Collections.ArrayList e quindi:

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

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

2

Una soluzione semplice consiste nell'impostare il valore predefinito di un'impostazione su null nella proprietà, ma nel costruttore verificare se la proprietà è null e, in tal caso, impostarla sul valore predefinito effettivo. Quindi, se desideri un array di 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;
        }
    }
}

Sembra un po 'hacky, ma è pulito e funziona come desiderato poiché le proprietà vengono inizializzate alle ultime impostazioni (o predefinite) prima che il costruttore venga chiamato.


2
Il designer per i file di impostazione dell'applicazione genera automaticamente il codice, quindi una modifica come questa verrebbe sovrascritta ogni volta che qualcuno utilizza il designer, anche accidentalmente.
— Carl G,

1

Usato System.Object.

Esempio:

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

Estratto:

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

1
Ho provato a utilizzare System.Object, ma le impostazioni non persistevano tra le sessioni. (Sì, era una build di rilascio, installazione autonoma, qualunque cosa tu voglia chiamarla, non stavo eseguendo il debug usando l'IDE)
— Emanuel Vintilă

0

Penso che tu abbia ragione riguardo alla serializzazione delle tue impostazioni. Vedi la mia risposta a questa domanda per un esempio:

Tecniche per condividere una configurazione tra due app?

Avresti una proprietà che è un array, come questa:

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

0

Crea alcune funzioni che convertono un array int in una stringa, ma tra ciascuna inserisci un carattere come "" (spazio).

Quindi, se la matrice è {1,34,546,56}, la stringa sarebbe "1 34 645 56"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.