TOC

This article has been localized into Russian by the community.

Отражение:

Отражение класса настроек

Итак, я решил закончить эту часть урока об отражении классным и полезным примером. Он немного больше, чем обычные примеры здесь на сайте, но, надеюсь, вы найдете его действительно полезным. Он использует кучу вещей, которые мы изучили в течение последних пары глав, так что вы можете идти в ногу.

Распространенным сценарием при создании любого приложения является желание сохранить настройки пользователей. Когда вы получите несколько настроек, вы, вероятно, создадите класс настроек, который будет обрабатывать загрузку и сохранение необходимых настроек. Каждый раз, когда вам понадобится новая настройка в классе настроек, вам придется обновлять методы Load() и Save (), чтобы включить эту новую настройку. Но Эй, почему бы не позволить классу Settings обнаружить свои собственные свойства, а затем загрузить и сохранить их автоматически? С Reflection это довольно легко, и если Вы прочитали другие главы в разделе Reflection этого учебника, вы должны быть в состоянии понять следующий пример.

Чтобы лучше вписать всё это в небольшой пример, я буду сохранять информацию о человеке вместо настроек приложения. Надеюсь, вы все равно получите общее представление. Имейте в виду — алгоритм с использованием Отражения работает МЕДЛЕННЕЕ, чем чтение и запись известных свойств вручную — это следует учитывать, когда вам требуется наиболее быстрый подход. Кроме того, в нашем примере мы используем обычный текстовый файл для хранения наших простых значений, разделенных только символом '|' . Если вы собираетесь использовать это в реальных проектах — вам, вероятно, понадобится лучший формат для ваших данных (возможно XML). Само собой, в данном примере так-же не хватает обработчиков ошибок, поэтому вам вероятно следует добавить парочку.

Хорошо, давайте начнем. Во-первых, наш класс Person, который Вы можете просто переименовать в Settings или что-то в этом роде, чтобы сделать его более полезным для вас:

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

Ладно, я знаю, здесь много всего интересного. Но я помогу тебе пройти через весь класс. Прежде всего, у нас есть несколько личных полей для хранения информации о нашей персоне. В нижней части класса у нас есть соответствующие открытые свойства, которые, конечно же, используют личные поля.

У нас также есть метод load (). Он ищет настройки файла.dat, и если он существует, он считывает весь файл и помещает каждую его строку в массив строк. Теперь мы проходим через каждую строку настроек и разделяем ее на две части: имя свойства и часть значения. Если оба присутствуют, мы просто используем объект Type, чтобы получить свойство с именем свойства, а затем мы устанавливаем значение для него, используя наш собственный метод SetProperty.

Метод SetProperty () смотрит на тип свойства, которое должно быть изменено, и затем действует соответственно. Сейчас он поддерживает только целые числа и строки, но, как вы, вероятно, понимаете, расширить эту поддержку будет довольно легко.

Метод Save () получает массив экземпляров PropertyInfo, по одному для каждого из определенных свойств класса Person, а затем использует TextWriter для записи каждого свойства и его значения в файл данных.

Теперь нам просто нужен код для использования этого класса. Это небольшое приложение попытается загрузить индивида из файла настроек, и если это не удастся, пользователю будет предложено ввести информацию:

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

Все здесь довольно тривиально, за исключением той части, где мы запрашиваем у пользователя информацию. Еще раз, мы используем отражение, чтобы получить все публичные свойства класса Person, а затем запрашиваем каждое из них.

В качестве упражнения для чтения я предлагаю вам расширить класс Person, чтобы включить больше информации. Просто добавьте в него дополнительные свойства, и вы увидите, что эта информация также сохраняется и загружается.


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!