So speichern Sie das Array int [] in den Anwendungseinstellungen


93

Ich erstelle eine einfache Windows Forms-Anwendung mit C # Express 2008. Ich bin ein erfahrener C ++ - Entwickler, aber ich bin ziemlich neu in C # und .NET.

Ich speichere derzeit einige meiner einfachen Anwendungseinstellungen mithilfe des Einstellungsdesigners und des folgenden Codes:

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

Jetzt möchte ich entweder ein Array von ints ( int[]) oder möglicherweise eine Liste von ints ( List< int >) als Einstellung speichern . Ich kann jedoch nicht herausfinden, wie das geht. Ich habe die Dokumentation, den Stackoverflow und Google durchsucht und kann keine anständige Erklärung dafür finden.

Aufgrund der wenigen Beispiele, die ich gefunden habe, muss ich eine serialisierbare Klasse erstellen, die mein Array oder meine Liste umschließt, und dann kann ich diesen Typ im Einstellungsdesigner verwenden. Ich bin mir jedoch nicht sicher, wie ich das genau machen soll.

Antworten:


136

Es gibt auch eine andere Lösung - erfordert ein wenig manuelle Bearbeitung der Einstellungsdatei, funktioniert danach jedoch in der VS-Umgebung und im Code einwandfrei. Und erfordert keine zusätzlichen Funktionen oder Wrapper.

Die Sache ist, dass VS es erlaubt, den int[]Typ standardmäßig in der Einstellungsdatei zu serialisieren - es erlaubt Ihnen nur nicht, ihn standardmäßig auszuwählen. Erstellen Sie also eine Einstellung mit dem gewünschten Namen (z. B. SomeTestSetting) und machen Sie sie von einem beliebigen Typ (z string. B. standardmäßig). Speichern Sie die Änderungen.

Gehen Sie nun zu Ihrem Projektordner und öffnen Sie die Datei "Properties \ Settings.settings" mit dem Texteditor (z. B. Editor). Sie können sie auch in VS öffnen, indem Sie im Projektmappen-Explorer mit der rechten Maustaste auf "-> Eigenschaften -> Settings.settings" klicken ", wählen Sie" Öffnen mit ... "und dann entweder" XML-Editor "oder" Quellcode-Editor ". Suchen Sie in den geöffneten XML-Einstellungen Ihre Einstellung (sie sieht folgendermaßen aus):

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

Ändern Sie den Parameter "Typ" von System.Stringin System.Int32[]. Jetzt sieht dieser Abschnitt folgendermaßen aus:

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

Speichern Sie nun die Änderungen und öffnen Sie die Projekteinstellungen erneut - voilà! - Wir haben die Einstellung SomeTestSetting mit Typ, auf System.Int32[]die über VS Settings Designer (auch Werte) sowie im Code zugegriffen und diese bearbeitet werden kann.


5
Genial. Um mit dem Editor in Visual Studio etwas in die Einstellung einzugeben, sollten Sie Folgendes einfügen. Dies ist für ein Zeichenfolgenarray, das ich benötigt habe. <? 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 .. verstehe nicht, warum dies nicht akzeptiert wurde Antwort .. kein zusätzlicher Code erforderlich (nur eine Zeile der vorhandenen XML ändern) und Sie erhalten Typensicherheit und volle vs Designer-Unterstützung!
Chris

1
Chris, danke :) Die Sache ist, ich habe meine Antwort viel später als die ursprünglich akzeptierte Antwort hinzugefügt (ungefähr ein Jahr später, tatsächlich :)). Ich teile nur die Erfahrung :)
Jen-Ari

6
Für alle Neugierigen würde die XML-Syntax der Konfigurationsdatei für int[](außer hübsch gedruckt) folgendermaßen <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>
aussehen

1
Einverstanden, das ist eine bessere Antwort, also habe ich die Marke geändert.
Sidewinderguy

40

lagern:

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

neu erstellen:

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

Edit: Abel Vorschlag!


Ok, das sieht so aus, als würden Sie die Daten manuell in eine Zeichenfolge serialisieren und umgekehrt. Ich denke, das würde funktionieren, ich könnte die Daten einfach als String-Einstellung speichern. Ich dachte daran, so etwas zu tun, aber ich suchte nach etwas "saubererem" oder "normalem" oder einfach mehr .NET'ish. Ich werde dies jedoch berücksichtigen, wenn nichts Besseres auftaucht. Vielen Dank.
Sidewinderguy

Hallo, dann würde ich mit McKays Allee gehen! (Konfigurationsabschnitt / Abschnittsgruppe)
Mike Gleason jr. Couturier

Ich werde damit weitermachen, weil es einfach ist. Vielen Dank für alle Ideen, ich bin sicher, sie werden auf dem Weg helfen.
Sidewinderguy

2
Hinweis: Sie müssen System.LinqIhre Verwendungen / Importe ergänzt haben, damit der oben genannte Trick funktioniert.
Sean Hanley

11

Es gibt einen anderen Weg, um dieses Ergebnis zu erzielen, der viel sauberer in der Verwendung ist, aber mehr Code erfordert. Bei der Implementierung eines benutzerdefinierten Typs und Typkonverters ist der folgende Code möglich:

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

Um dies zu erreichen, benötigen Sie einen Typ mit einem Typkonverter, der die Konvertierung in und von Zeichenfolgen ermöglicht. Sie tun dies, indem Sie den Typ mit dem TypeConverterAttribute dekorieren:

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

Implementieren Sie dann diesen Typkonverter als Ableitung von 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);
    }
}

Durch die Bereitstellung einiger praktischer Methoden für die MyNumberArray-Klasse, die wir dann sicher der und von List zuweisen können, würde die gesamte Klasse ungefähr so ​​aussehen:

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

Um dies in den Einstellungen zu verwenden, fügen Sie die obigen Klassen zu einer Assembly hinzu und kompilieren sie. In Ihrem Settings.settings-Editor klicken Sie einfach auf die Option "Durchsuchen" und wählen die MyNumberArray-Klasse aus.

Auch dies ist viel mehr Code; Es kann jedoch auf viel kompliziertere Datentypen angewendet werden als ein einfaches Array.


Danke das sieht interessant aus. Ich werde es ausprobieren, wenn ich die Chance dazu bekomme.
Sidewinderguy

3

Geben Sie die Einstellung als System.Collections.ArrayList an und dann:

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

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

2

Eine einfache Lösung besteht darin, den Standardwert einer Einstellung in der Eigenschaft auf null zu setzen. Überprüfen Sie jedoch im Konstruktor, ob die Eigenschaft null ist, und setzen Sie sie in diesem Fall auf den tatsächlichen Standardwert. Wenn Sie also eine Reihe von Ints möchten:

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

Es fühlt sich irgendwie hackig an, ist aber sauber und funktioniert wie gewünscht, da die Eigenschaften auf ihre letzten (oder Standardeinstellungen) initialisiert werden, bevor der Konstruktor aufgerufen wird.


2
Der Designer für Anwendungseinstellungsdateien generiert den Code automatisch, sodass eine solche Änderung jedes Mal überschrieben wird, wenn jemand den Designer verwendet, auch aus Versehen.
Carl G

1

Gebraucht System.Object.

Beispiel:

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

Extrakt:

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

1
Ich habe versucht, System.Object zu verwenden, aber die Einstellungen blieben zwischen den Sitzungen nicht erhalten. (Ja, es war ein Release-Build, eine eigenständige Installation, wie auch immer Sie es nennen möchten, ich habe nicht mit der IDE debuggt)
Emanuel Vintilă

0

Ich denke, Sie haben Recht mit der Serialisierung Ihrer Einstellungen. Ein Beispiel finden Sie in meiner Antwort auf diese Frage:

Techniken zum Teilen einer Konfiguration zwischen zwei Apps?

Sie hätten eine Eigenschaft, die ein Array ist, wie folgt:

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

0

Erstellen Sie einige Funktionen, die ein int-Array in eine Zeichenfolge konvertieren, zwischen denen jedoch ein Zeichen wie "" (Leerzeichen) steht.

Wenn das Array also {1,34,546,56} ist, wäre die Zeichenfolge "1 34 645 56".

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.