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.