TOC

This article has been localized into Portuguese by the community.

Reflection:

Uma classe de configurações baseada em reflexão

Ok, então eu pensei que eu iria terminar esta parte do tutorial sobre Reflexão, com um exemplo legal e útil. É um pouco maior do que os exemplos habituais aqui no site, mas espero que você ache realmente útil. Ele usa um monte de coisas que analisamos durante os últimos dois capítulos, então esperamos que você possa acompanhar.

Um cenário comum ao criar qualquer tipo de aplicativo é o desejo de salvar as configurações dos usuários. Quando você obtiver várias configurações, provavelmente criará uma classe Settings, que manipulará o carregamento e o salvamento das configurações desejadas. Toda vez que você precisar de uma nova configuração na sua classe Configurações, você terá que atualizar os métodos Load() e Save(), para incluir essa nova configuração. Mas, ei, por que não deixar a classe Settings descobrir suas próprias propriedades e depois carregá-las e salvá-las automaticamente? Com o Reflection, é muito fácil, e se você leu os outros capítulos na seção Reflexão deste tutorial, será capaz de entender o exemplo a seguir.

Para fazer com que ele se encaixe melhor em um pequeno exemplo, estou salvando informações sobre uma pessoa em vez de configurações do aplicativo, mas esperamos que você tenha a idéia geral de qualquer maneira. Por favor, esteja ciente de que o uso do Reflection SERÁ mais lento do que ler e escrever propriedades conhecidas manualmente, então você deve considerar quando usá-lo e quando optar por uma abordagem mais rápida! Além disso, em nosso exemplo, usamos um arquivo de texto simples para armazenar valores ainda mais simples, separados apenas por um | (caractere de pipe). Se você estiver usando isso para coisas do mundo real, provavelmente desejará um formato melhor para seus dados, talvez XML. E, claro, não há muito tratamento de erros, então você provavelmente deve adicionar um pouco disso também.

Ok, vamos começar. Primeiro, nossa classe Person, que você pode simplesmente renomear para Configurações ou algo assim, para torná-la mais útil para você:

public class Person
{
    private int age = -1;
    private string name = String.Empty;

    public void Load()
    {
        if(File.Exists("settings.dat"))
        {
            Type type = this.GetType();

            string propertyName, value;
            string[] temp;
            char[] splitChars = new char[] { '|' };
            PropertyInfo propertyInfo;

            string[] settings = File.ReadAllLines("settings.dat");
            foreach(string s in settings)
            {
                temp = s.Split(splitChars);
                if(temp.Length == 2)
                {
                    propertyName = temp[0];
                    value = temp[1];
                    propertyInfo = type.GetProperty(propertyName);
                    if(propertyInfo != null)
                        this.SetProperty(propertyInfo, value);
                }
            }
        }
    }

    public void Save()
    {
        Type type = this.GetType();
        PropertyInfo[] properties = type.GetProperties();
        TextWriter tw = new StreamWriter("settings.dat");
        foreach(PropertyInfo propertyInfo in properties)
        {
            tw.WriteLine(propertyInfo.Name + "|" + propertyInfo.GetValue(this, null));
        }
        tw.Close();
    }

    public void SetProperty(PropertyInfo propertyInfo, object value)
    {
        switch(propertyInfo.PropertyType.Name)
        {
            case "Int32":
                propertyInfo.SetValue(this, Convert.ToInt32(value), null);
                break;
            case "String":
                propertyInfo.SetValue(this, value.ToString(), null);
                break;
        }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

Ok, tem muita coisa, eu sei. Mas eu vou te ajudar durante toda a aula. Em primeiro lugar, temos alguns campos privados para guardar informações sobre nossa pessoa. Na parte inferior da classe, temos as propriedades públicas correspondentes que usam os campos privados, é claro.

Nós também temos um método Load(). Ele procura o arquivo settings.dat e, se existir, lê o arquivo inteiro e coloca cada linha dele em uma matriz de strings. Agora, percorremos cada linha de configuração e a dividimos em duas partes: um nome de propriedade e uma parte de valor. Se ambos estiverem presentes, simplesmente usamos o objeto Type para obter a propriedade com o nome da propriedade e, em seguida, definimos o valor para ela usando nosso próprio método SetProperty.

O método SetProperty() examina o tipo da propriedade prestes a ser alterada e, em seguida, age de maneira correspondente. No momento, ele suporta apenas inteiros e strings, mas como você provavelmente percebe, estender esse suporte seria bem fácil.

O método Save() obtém uma matriz de instâncias PropertyInfo, uma para cada uma das propriedades definidas na classe Person e, em seguida, usa um TextWriter para gravar cada propriedade e seu valor no arquivo de dados.

Agora só precisamos de algum código para usar essa classe. Este pequeno aplicativo tentará carregar a pessoa do arquivo de configurações e, se ela não for bem-sucedida, o usuário será solicitado a fornecer as informações:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        person.Load();
        if((person.Age > 0) && (person.Name != String.Empty))
        {
            Console.WriteLine("Hi " + person.Name + " - you are " + person.Age + " years old!");
        }
        else
        {
            Console.WriteLine("I don't seem to know much about you. Please enter the following information:");
            Type type = typeof(Person);
            PropertyInfo[] properties = type.GetProperties();
            foreach(PropertyInfo propertyInfo in properties)
            {
                Console.WriteLine(propertyInfo.Name + ":");
                person.SetProperty(propertyInfo, Console.ReadLine());
            }
            person.Save();
            Console.WriteLine("Thank you! I have saved your information for next time.");
        }
        Console.ReadKey();
    }
}

Tudo aqui é bem trivial, exceto na parte em que pedimos informações ao usuário. Mais uma vez, usamos Reflection para obter todas as propriedades públicas da classe Person e, em seguida, solicitamos cada uma delas.

Como exercício de leitura, sugiro que você estenda a classe Person para incluir mais informações. Basta adicionar mais propriedades a ele e você verá que essas informações são salvas e carregadas também.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!