TOC

This article has been localized into German by the community.

Reflektion:

Eine Einstellungs-Klasse auf Reflektionsbasis

Okay, ich dachte, ich würde diesen Teil des Tutorials über Reflection mit einem coolen und nützlichen Beispiel beenden. Es ist etwas größer als die üblichen Beispiele hier auf der Website, aber hoffentlich finden Sie es wirklich nützlich. Es verwendet eine Menge von dem, was wir uns in den letzten Kapiteln angesehen haben, hoffentlich können Sie hier mithalten.

Ein übliches Szenario beim Erstellen einer beliebigen Anwendung ist der Wunsch, die Benutzereinstellungen zu speichern. Wenn Sie mehrere Einstellungen erhalten, erstellen Sie wahrscheinlich eine Settings-Klasse, die das Laden und Speichern der gewünschten Einstellungen übernimmt. Jedes Mal, wenn Sie eine neue Einstellung in Ihrer Settings-Klasse benötigen, müssen Sie die Methoden Load() und Save() aktualisieren, um diese neue Einstellung aufzunehmen. Aber hey, warum lassen die Settings-Klasse nicht ihre eigenen Eigenschaften entdecken und laden und speichern sie dann automatisch? Mit Reflection ist das ganz einfach. Wenn Sie die anderen Kapitel im Abschnitt "Reflection" dieses Tutorials gelesen haben, sollten Sie das folgende Beispiel verstehen können.

Damit es besser in ein kleines Beispiel passt, speichere ich Informationen zu einer Person anstelle von Anwendungseinstellungen, aber hoffentlich erhalten Sie trotzdem eine allgemeine Vorstellung. Bitte beachten Sie, dass die Verwendung von Reflection langsamer ist als das manuelle Lesen und Schreiben bekannter Eigenschaften. Daher sollten Sie überlegen, wann sie verwendet werden sollten und wann Sie sich für einen schnelleren Ansatz entscheiden sollten. In unserem Beispiel verwenden wir eine einfache Textdatei zum Speichern von noch einfacheren Werten, nur durch | getrennt ("Pipe-Zeichen"). Wenn Sie dies für echte Dinge verwenden, möchten Sie wahrscheinlich ein besseres Format für Ihre Daten, vielleicht XML. Und natürlich gibt es nicht viel Fehlerbehandlung, deshalb sollten Sie wahrscheinlich auch etwas davon hinzufügen.

Okay, lassen Sie uns anfangen. Zuerst unsere Person-Klasse, die Sie einfach in Einstellungen oder ähnliches umbenennen können, um es für Sie nützlicher zu machen:

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

Okay, es gibt eine Menge Zeug, ich weiß. Aber ich werde Ihnen durch die gesamte Klasse helfen. Zunächst haben wir ein paar private Felder, in denen Informationen über unsere Person gespeichert werden. Im unteren Teil der Klasse haben wir die entsprechenden öffentlichen Eigenschaften, die natürlich die privaten Felder verwenden.

Wir haben auch eine Load()-Methode. Es wird nach der Datei "settings.dat" gesucht. Wenn sie existiert, liest sie die gesamte Datei und platziert jede Zeile in einem String-Array. Jetzt durchlaufen wir jede Einstellungszeile und teilen sie in zwei Teile auf: Einen Eigenschaftsnamen und einen Wertteil. Wenn beides vorhanden ist, verwenden wir einfach das Type-Objekt, um die Eigenschaft mit dem Namen der Eigenschaft abzurufen, und legen dann den Wert mithilfe der eigenen SetProperty-Methode fest.

Die SetProperty()-Methode prüft den Typ der zu ändernden Eigenschaft und handelt dann entsprechend. Im Moment werden nur ganze Zahlen und Strings unterstützt, aber wie Sie wahrscheinlich wissen, wäre das Erweitern dieser Unterstützung ziemlich einfach.

Die Save()-Methode ruft ein Array von PropertyInfo-Instanzen ab, eines für jede der definierten Eigenschaften der Person-Klasse, und verwendet dann einen TextWriter, um jede Eigenschaft und ihren Wert in die Datendatei zu schreiben.

Jetzt brauchen wir nur etwas Code, um diese Klasse zu verwenden. Diese kleine Anwendung versucht, die Person aus der Einstellungsdatei zu laden. Wenn dies nicht gelingt, wird der Benutzer zur Eingabe der Informationen aufgefordert:

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

Alles hier ist ziemlich trivial, mit Ausnahme des Teils, in dem wir den Benutzer um Informationen bitten. Wieder verwenden wir Reflection, um alle öffentlichen Eigenschaften der Person-Klasse abzurufen, und fragen dann nach jeder von ihnen.

Als Leseübung empfehle ich Ihnen, die Person-Klasse um weitere Informationen zu erweitern. Fügen Sie einfach weitere Eigenschaften hinzu, und Sie werden sehen, dass diese Informationen auch gespeichert und geladen werden.


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!