Как сохранить массив int [] в настройках приложения
Я создаю простое приложение Windows Forms с помощью С# express 2008. Я опытный разработчик на С++, но я совершенно новый для С# и .NET.
В настоящее время я сохраняю некоторые из моих простых настроек приложения, используя конструктор параметров и код, подобный этому:
// Store setting
Properties.Settings.Default.TargetLocation = txtLocation.Text;
...
// Restore setting
txtLocation.Text = Properties.Settings.Default.TargetLocation;
Теперь я хотел бы сохранить как массив ints (int[]
), так и, возможно, List of ints (List< int >
) в качестве параметра. Однако я не могу понять, как это сделать. Я искал документацию, stackoverflow и google, и я не могу найти достойное объяснение, как это сделать.
Моя догадка, основанная на редких примерах, которые я нашел, заключается в том, что мне нужно создать класс, который является сериализуемым, который обертывает мой массив или List, а затем я смогу использовать этот тип в дизайнере настроек. Однако я точно не знаю, как это сделать.
Заранее благодарим за помощь!
Ответы
Ответ 1
Существует еще одно решение - требуется небольшое ручное редактирование файла настроек, но впоследствии отлично работает в среде VS и в коде. И не требует дополнительных функций или оберток.
Дело в том, что VS разрешает сериализовать int[]
по умолчанию в файле настроек - он просто не позволяет вам выбирать его по умолчанию.
Итак, создайте параметр с нужным именем (например, SomeTestSetting) и сделайте его любым типом (например, string
по умолчанию).
Сохраните изменения.
Теперь перейдите в папку проекта и откройте файл "Свойства\Настройки .settings" с помощью текстового редактора (например, "Блокнот" ). Или вы можете открыть его в VS, щелкнув правой кнопкой мыши в обозревателе решений на "- > Свойства → Settings.settings", выберите "Открыть с...", а затем выберите "Редактор 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>
Теперь сохраните изменения и заново откройте настройки проекта - voilà! - У нас есть настройка SomeTestSetting с типом System.Int32[]
, к которому можно получить доступ и отредактировать с помощью VS Settings Designer (значения тоже), а также в коде.
Ответ 2
для хранения:
string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());
для повторного создания:
int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();
Изменить: предложение Абеля!
Ответ 3
Существует еще один способ добиться этого результата, который намного более чист в использовании, но требует большего количества кода. Мое внедрение настраиваемого типа и преобразователя типов возможно:
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(); }
}
Наконец, чтобы использовать это в настройках, вы добавляете вышеуказанные классы в сборку и компилируете. В редакторе Settings.settings вы просто нажмете "Обзор" и выберите класс MyNumberArray и отпустите.
Снова это намного больше кода; однако он может быть применен к гораздо более сложным типам данных, чем простой массив.
Ответ 4
Задайте настройку как System.Collections.ArrayList, а затем:
Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 });
int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
Ответ 5
Простое решение - установить значение по умолчанию для значения 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;
}
}
}
Он чувствует себя взломанным, но его чистым и работает по своему желанию, поскольку свойства инициализируются до последних (или по умолчанию) параметров перед вызовом конструктора.
Ответ 6
Используется System.Object
.
Пример:
byte[] arBytes = new byte[] { 10, 20, 30 };
Properties.Settings.Default.KeyObject = arBytes;
Extract:
arBytes = (byte[])Properties.Settings.Default.KeyObject;
Ответ 7
Я думаю, вы правы в сериализации своих настроек. См. Мой ответ на этот вопрос для образца:
Способы совместного использования конфигурации между двумя приложениями?
У вас будет свойство, которое представляет собой массив, например:
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int [] Numbers { get; set; }
Ответ 8
Сделайте некоторые функции, которые преобразуют массив int в строку, но между ними помещается символ типа "" (пробел).
Итак, если массив равен {1,34,546,56}, строка будет "1 34 645 56"