Tworzę prostą aplikację Windows Forms przy użyciu C # express 2008. Jestem doświadczonym programistą C ++, ale jestem prawie zupełnie nowy w C # i .NET.
Obecnie przechowuję niektóre z moich prostych ustawień aplikacji przy użyciu projektanta ustawień i kodu w ten sposób:
// Store setting
Properties.Settings.Default.TargetLocation = txtLocation.Text;
...
// Restore setting
txtLocation.Text = Properties.Settings.Default.TargetLocation;
Teraz chciałbym zapisać albo tablicę ints ( int[]
), albo prawdopodobnie Listę ints ( List< int >
), jako ustawienie. Jednak nie wiem, jak to zrobić. Przeszukałem dokumentację, stackoverflow i google i nie mogę znaleźć przyzwoitego wyjaśnienia, jak to zrobić.
Moje przeczucie oparte na nielicznych przykładach, które znalazłem, jest takie, że muszę utworzyć klasę, którą można serializować, która otacza moją tablicę lub listę, a następnie będę mógł użyć tego typu w projektancie ustawień. Jednak nie jestem pewien, jak to zrobić.
int[]
wyglądałaby tak (z wyjątkiem ładnie wydrukowanego):<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>
przechować:
string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());
odtworzyć:
int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();
Edycja: sugestia Abela!
źródło
System.Linq
powyższa sztuczka zadziałała, musisz dodać do swoich zastosowań / importów.Jest jeszcze jeden sposób na osiągnięcie tego wyniku, który jest dużo czystszy w użyciu, ale wymaga więcej kodu. Mój implementujący niestandardowy typ i konwerter typów jest możliwy następujący kod:
List<int> array = Settings.Default.Testing; array.Add(new Random().Next(10000)); Settings.Default.Testing = array; Settings.Default.Save();
Aby to osiągnąć, potrzebujesz typu z konwerterem typów, który umożliwia konwersję do iz ciągów. Robisz to, dekorując typ za pomocą TypeConverterAttribute:
[TypeConverter(typeof(MyNumberArrayConverter))] public class MyNumberArray ...
Następnie implementujemy ten konwerter typu jako wyprowadzenie 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); } }
Zapewniając kilka wygodnych metod w klasie MyNumberArray, którą możemy następnie bezpiecznie przypisać do iz listy, cała klasa wyglądałaby mniej więcej tak:
[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(); } }
Na koniec, aby użyć tego w ustawieniach, dodajesz powyższe klasy do zestawu i kompilujesz. W edytorze Settings.settings wystarczy kliknąć opcję „Browse”, wybrać klasę MyNumberArray i gotowe.
Znowu jest to dużo więcej kodu; Jednak można go zastosować do znacznie bardziej skomplikowanych typów danych niż prosta tablica.
źródło
Określ ustawienie jako System.Collections.ArrayList, a następnie:
Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 }); int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
źródło
Prostym rozwiązaniem jest ustawienie wartości domyślnej ustawienia na null we właściwości, ale w konstruktorze sprawdź, czy właściwość ma wartość null, a jeśli tak, ustaw ją na rzeczywistą wartość domyślną. Więc jeśli chcesz mieć tablicę liczb 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; } } }
Wydaje się trochę hacky, ale jest czysty i działa zgodnie z oczekiwaniami, ponieważ właściwości są inicjowane do ich ostatnich (lub domyślnych) ustawień przed wywołaniem konstruktora.
źródło
Używany
System.Object
.Przykład:
byte[] arBytes = new byte[] { 10, 20, 30 }; Properties.Settings.Default.KeyObject = arBytes;
Wyciąg:
arBytes = (byte[])Properties.Settings.Default.KeyObject;
źródło
Myślę, że masz rację co do serializacji ustawień. Zobacz moją odpowiedź na to pytanie dla próbki:
Techniki udostępniania konfiguracji między dwiema aplikacjami?
Będziesz miał właściwość, która jest tablicą, na przykład:
/// <summary> /// Gets or sets the height. /// </summary> /// <value>The height.</value> [XmlAttribute] public int [] Numbers { get; set; }
źródło
Stwórz kilka funkcji, które konwertują tablicę int w łańcuch, ale między nimi wstaw znak taki jak "" (spacja).
Więc jeśli tablicą jest {1,34,546,56}, ciąg będzie miał postać „1 34 645 56”
źródło