Как сохранить int [] массив в настройках приложения
Я создаю простое приложение windows Forms с помощью C# express 2008. Я опытный разработчик C++, но я в значительной степени новичок в C# и. NET.
В настоящее время я храню некоторые из моих простых настроек приложения с помощью конструктора настроек и кода следующим образом:
// Store setting
Properties.Settings.Default.TargetLocation = txtLocation.Text;
...
// Restore setting
txtLocation.Text = Properties.Settings.Default.TargetLocation;
Теперь я хотел бы сохранить либо массив ints ( int[]
), или, возможно, список ints (List< int >
), в качестве параметра. Однако я не могу понять, как это сделать. Я искал документация, stackoverflow и google, и я не могу найти достойного объяснения того, как это сделать.
моя догадка, основанная на редких примерах, которые я нашел, заключается в том, что мне нужно создать сериализуемый класс, который обертывает мой массив или список, а затем я смогу использовать этот тип в конструкторе настроек. Однако я точно не знаю, как это сделать.
8 ответов:
есть и другое решение-требуется немного ручного редактирования файла настроек, но впоследствии отлично работает в среде VS и в коде. И не требует никаких дополнительных функций или фантики.
дело в том, что VS позволяет сериализовать
int[]
тип по умолчанию в файле настроек - это просто не позволяет выбрать его по умолчанию. Итак, создайте настройку с нужным именем (например, SomeTestSetting) и сделайте ее любого типа (например,string
по умолчанию). Сохранить изменения.Теперь перейдите в папку проекта и откройте "Свойства\настройки.настройки "файл с текстовым редактором (Блокнот, например) или вы можете открыть его в VS, щелкнув правой кнопкой мыши в обозревателе решений на" - > свойства - > настройки.настройки", выберите "Открыть с помощью..."а затем выберите либо "редактор XML", либо "редактор исходного кода (текста)". В открытых настройках xml найдите свою настройку (она будет выглядеть так):
<Setting Name="SomeTestSetting" Type="System.String" Scope="User"> <Value Profile="(Default)" /> </Setting>
измените параметр" тип " с
System.String
доSystem.Int32[]
. Теперь это раздел будет выглядеть так:<Setting Name="SomeTestSetting" Type="System.Int32[]" Scope="User"> <Value Profile="(Default)" /> </Setting>
теперь сохраните изменения и снова откройте настройки проекта - вуаля! - У нас есть установка SomeTestSetting с типом
System.Int32[]
которые могут быть доступны и отредактированы через VS Settings Designer (значения тоже), а также в коде.
в магазине:
string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());
чтобы воссоздать:
int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();
редактировать: предложение Абеля!
есть еще один способ достичь этого результата, который намного чище в использовании, но требует больше кода. Моя реализация пользовательского типа и преобразователя типов возможен следующий код:
List<int> array = Settings.Default.Testing; array.Add(new Random().Next(10000)); Settings.Default.Testing = array; Settings.Default.Save();
для этого вам нужен тип с преобразователем типов, который позволяет преобразовывать строки и из строк. Вы делаете это, украшая тип с TypeConverterAttribute:
[TypeConverter(typeof(MyNumberArrayConverter))] public class MyNumberArray ...
затем реализация этого преобразователя типа как производного 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); } }
предоставляя некоторые удобные методы в классе MyNumberArray, которые мы можем безопасно назначить и из списка, полный класс будет выглядеть примерно так:
[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(); } }
наконец, чтобы использовать это в настройках, вы добавляете вышеуказанные классы в сборку и компилируете. В ваших настройках.редактор настроек вы просто нажимаете кнопку" Обзор " и выбираете класс MyNumberArray, и вы идете.
опять же это намного больше кода; однако, это может применяться к гораздо более сложным типам данных, чем простой массив.
укажите параметр в качестве системного.Коллекции.ArrayList и затем:
Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 }); int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
простое решение состоит в том, чтобы установить значение по умолчанию для параметра null в свойстве, но в конструкторе проверьте, является ли свойство null, и если да, то установите его в фактическое значение по умолчанию. Так что если вы хотите массив ints:
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; } } }
он чувствует себя немного хаки, но его чистый и работает по желанию, так как свойства инициализируются до их последних (или по умолчанию) настроек перед вызовом конструктора.
использовать
System.Object
.пример:
byte[] arBytes = new byte[] { 10, 20, 30 }; Properties.Settings.Default.KeyObject = arBytes;
выдержка:
arBytes = (byte[])Properties.Settings.Default.KeyObject;
Я думаю, что вы правы насчет сериализации настроек. Смотрите мой ответ на этот вопрос для примера:
методы для совместного использования конфигурации между двумя приложениями?
у вас будет свойство, которое является массивом, например:
/// <summary> /// Gets or sets the height. /// </summary> /// <value>The height.</value> [XmlAttribute] public int [] Numbers { get; set; }