Como armazenar o array int [] nas configurações do aplicativo

93

Estou criando um aplicativo Windows Forms simples usando C # express 2008. Sou um desenvolvedor C ++ experiente, mas sou praticamente novo em C # e .NET.

No momento, estou armazenando algumas das configurações simples do meu aplicativo usando o designer de configurações e um código como este:

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

Agora eu gostaria de armazenar um array de ints ( int[]), ou possivelmente uma Lista de ints ( List< int >), como uma configuração. No entanto, não consigo descobrir como fazer isso. Eu pesquisei a documentação, stackoverflow e google, e não consigo encontrar uma explicação decente de como fazer isso.

Meu palpite com base nos exemplos esparsos que encontrei é que tenho que criar uma classe que seja serializável que envolva meu array ou Lista, e então poderei usar esse tipo no designer de configurações. No entanto, não sei exatamente como fazer isso.

cara lateral
fonte

Respostas:

136

Há também outra solução - requer um pouco de edição manual do arquivo de configurações, mas depois funciona bem no ambiente VS e no código. E não requer funções ou invólucros adicionais.

O fato é que o VS permite serializar o int[]tipo por padrão no arquivo de configurações - ele apenas não permite que você o selecione por padrão. Portanto, crie uma configuração com o nome desejado (por exemplo, SomeTestSetting) e faça-o de qualquer tipo ( stringpor exemplo, por padrão). Salve as alterações.

Agora vá para a pasta do seu projeto e abra o arquivo "Propriedades \ Settings.settings" com o editor de texto (Notepad, por exemplo). Ou você pode abri-lo no VS clicando com o botão direito no Solution Explorer em "-> Propriedades -> Settings.settings ", selecione" Abrir com ... "e, a seguir, escolha" Editor de XML "ou" Editor de código-fonte (texto) ". Nas configurações xml abertas, encontre sua configuração (será semelhante a esta):

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

Altere o parâmetro "Tipo" de System.Stringpara System.Int32[]. Agora, esta seção terá a seguinte aparência:

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

Agora salve as alterações e reabra as configurações do projeto - voilà! - Temos a configuração SomeTestSetting com tipo System.Int32[]que pode ser acessada e editada através do VS Settings Designer (valores também), assim como no código.

Jen-Ari
fonte
5
Impressionante. Para inserir algo na configuração usando o editor no Visual Studio, você deve colar algo assim, isto é para uma matriz de string, que era o que eu precisava <? 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 .. não entendo porque esta não foi aceita resposta .. nenhum código extra necessário (apenas modifique uma linha do xml existente) e você terá segurança de tipo e suporte completo vs designer!
Chris
1
Chris, obrigado :) Acontece que adicionei minha resposta muito mais tarde do que a resposta originalmente aceita (cerca de um ano depois, na verdade :)). No entanto, estou apenas compartilhando a experiência :)
Jen-Ari
6
Para qualquer pessoa curiosa, a sintaxe XML do arquivo de configuração para int[]seria semelhante a esta (exceto bem impressa):<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>
aaaantoine
1
Concordo, esta é uma resposta melhor, então mudei a marca.
sidewinderguy
40

armazenar:

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

para recriar:

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

Edit: sugestão de Abel!

Mike Gleason jr Couturier
fonte
Ok, então parece que você está serializando os dados manualmente em uma string e vice-versa. Eu acho que isso funcionaria, eu poderia simplesmente armazenar os dados como uma configuração de string. Pensei em fazer algo assim, mas estava procurando algo mais "limpo" ou "padrão" ou apenas mais .NET. Vou manter isso em mente, se nada melhor acontecer. Obrigado.
sidewinderguy
Olá, então eu iria com a avenida McKay! (seção de configuração / grupo de seção)
Mike Gleason jr Couturier
Vou continuar porque é simples. Obrigado por todas as ideias a todos, tenho certeza que vão ajudar no futuro.
sidewinderguy
2
Nota: Você precisará System.Linqadicionar seus usos / importações para que o truque acima funcione.
Sean Hanley
11

Existe uma outra maneira de obter esse resultado que é muito mais limpo no uso, mas requer mais código. Minha implementação de um tipo personalizado e conversor de tipo o seguinte código é possível:

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

Para conseguir isso, você precisa de um tipo com um conversor de tipo que permite a conversão de e para strings. Você faz isso decorando o tipo com o TypeConverterAttribute:

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

Em seguida, implementar este conversor de tipo como uma derivação de 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);
    }
}

Ao fornecer alguns métodos de conveniência na classe MyNumberArray, podemos atribuir com segurança a e a partir de List, a classe completa seria semelhante a:

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

Por último, para usar isso nas configurações, você adiciona as classes acima a uma montagem e compila. Em seu editor Settings.settings, você simplesmente clica na opção "Browse" e seleciona a classe MyNumberArray e pronto.

Novamente, isso é muito mais código; entretanto, pode ser aplicado a tipos de dados muito mais complicados do que uma simples matriz.

csharptest.net
fonte
Obrigado, isso parece interessante. Vou experimentar quando tiver oportunidade.
sidewinderguy de
3

Especifique a configuração como System.Collections.ArrayList e:

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

int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
Joao angelo
fonte
2

Uma solução simples é definir o valor padrão de uma configuração como nulo na propriedade, mas no construtor verifique se a propriedade é nula e, em caso afirmativo, defina-a com seu valor padrão real. Então, se você quiser uma matriz de 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;
        }
    }
}

Parece meio hacky, mas é limpo e funciona como desejado, já que as propriedades são inicializadas com suas últimas configurações (ou padrão) antes que o construtor seja chamado.

Russell Bearden
fonte
2
O designer de arquivos de configuração do aplicativo gera automaticamente o código e, portanto, uma alteração como essa seria sobrescrita sempre que alguém usasse o designer, mesmo acidentalmente.
Carl G
1

Usado System.Object.

Exemplo:

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

Extrair:

arBytes = (byte[])Properties.Settings.Default.KeyObject;
Eslavos
fonte
1
Tentei usar System.Object, mas as configurações não persistiam entre as sessões. (Sim, foi uma versão de construção, instalação autônoma, como você quiser chamá-la, eu não estava depurando usando o IDE)
Emanuel Vintilă
0

Acho que você está certo sobre serializar suas configurações. Veja minha resposta a esta pergunta para um exemplo:

Técnicas para compartilhar uma configuração entre dois aplicativos?

Você teria uma propriedade que é uma matriz, como esta:

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

Faça algumas funções que convertam um array int em uma string, mas entre cada um coloque um caractere como "" (espaço).

Portanto, se a matriz for {1,34,546,56} a string seria "1 34 645 56"

user1452079
fonte