Как сохранить 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 86

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

сделать некоторые функции, которые преобразуют массив int в строку, но между каждым положить символ, как "" (пробел).

Так что если массив { 1,34,546,56 } строка будет "1 34 645 56"