Laden...

Eigenschaften zur Laufzeit auslesen: Reflection, Type.GetProperties()

Erstellt von Ismoh vor 8 Jahren Letzter Beitrag vor 8 Jahren 3.837 Views
Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren
Eigenschaften zur Laufzeit auslesen: Reflection, Type.GetProperties()

Hallo Community,
lange her, dass ich mal wieder eine Frage habe:

Kann man zur Laufzeit auf den Namen eines Attributes zugreifen?


string titel = "ritter der kokosnuss"

Ich hatte mir überlegt Objekte via (mini)JSON zu speichern und möchte gerne das Objekt als Parameter übergeben und die Variablen/Attribute des Objekts auslesen, also auf "titel" als string zugreifen.
Da das Objekt unterschiedliche Attribute hat, fällt ein statisches Auslesen von Attributen weg:
Ich könnte die Attribute manuell festlegen, also: jedes Objekt hat die Variable "titel", "preis", usw - dem ist aber nicht so, deswegen die dynamische "Abfrage" wie viele und welche Attribute das Objekt hat.

Habe ich mich verständlich ausgedrückt ?
Ich freue mich über jegliche Form von Unterstützung.

5.658 Beiträge seit 2006
vor 8 Jahren

Hi Ismoh,

was du als Attribut bezeichnest, heißt in C# Feld. Attribute haben eine andere Bedeutung.

Warum willst du JSON verwenden? Handelt es sich um eine Web-Anwendung?

Ansonsten kannst du dein Problem mit Hilfe eines Dictionarys lösen, wie beispielsweise in [FAQ] Variablennamen zur Laufzeit zusammensetzen / Dynamisches Erzeugen von Controls beschrieben.

Christian

Weeks of programming can save you hours of planning

L
155 Beiträge seit 2012
vor 8 Jahren

Über Reflection würde das gehen.

Mit freundlichen Grüßen
lutzeslife

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

Hi MrSparkle,
es handelt sich um ein Spiel.
Ich möchte die Felder der Objekte in eine Datei speichern und habe gedacht, dass JSON eine Lösung dazu ist.

Die Dictionary ist nach Spielneustart nicht mehr vorhanden, deswegen nutze ich diese nicht.

Über Reflection würde das gehen.

Das hier ?
https://msdn.microsoft.com/de-de/library/z919e8tw

H
114 Beiträge seit 2007
vor 8 Jahren

Hallo Ismoh,

na wenn dann eher mittels Type.GetFields.

Wie bereits gesagt wurde, hat die Bezeichnung "Attribut" im Umfeld von .NET eine andere Bedeutung.

Ich möchte die Felder der Objekte in eine Datei speichern

Wenn es wirklich nur darum geht, dann kanst du dich auch mal mit dem Thema Serialisierung beschäftigen.Damit kannst du den Zustand eines Objekts binär, als XML, JSON, ... speichern.

Grüße, HiGHteK

4.939 Beiträge seit 2008
vor 8 Jahren

Aber wie MrSparkle schon schrieb, möchtest du keine Attribute sondern Felder, s. daher Reflektion in .NET Framework mit dem Stichwort FieldInfo.

5.658 Beiträge seit 2006
vor 8 Jahren

Zum Speichern der Spielstände würde sich Serialisierung/Deserialisierung anbieten, wobei ich XML oder Binärdaten JSON vorziehen würde. Oder man verwendet gleich das [Tutorial] Konfigurationsmodell im .NET Framework.

Christian

Weeks of programming can save you hours of planning

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

Ich habe mir eure Beiträge soeben angeguckt - eher überflogen als genau gelesen (habe gerade win10 Installationsprobleme).

GetField ist nur ab .NET 4 verfügbar, jedoch benutzt Unity5 nur .NET 2, also Serialisierung ?

Ich habe folgendes (https://bitbucket.org/alexzzzz/unity-c-5.0-and-6.0-integration/overview) vor einigen Tagen gesehen. Eine eurer Experten-Meinungen dazu wären nun sehr hilfreich.

Besteht also evtl. doch die Möglichkeit GetField zu benutzen?

Wieso würdet Ihr eher XML anstatt JSON nutzen?

Entschuldigt meine Bombardierung von Fragen.

5.658 Beiträge seit 2006
vor 8 Jahren

Hi Ismoh,

ich empfehle dir, deine Installationsprobleme zu beheben und danach ersteinmal in Ruhe die verlinkten Beiträge zu lesen und evtl. weiter zu recherchieren. Dann kannst du die Vor- und Nachteile gegeneinander abwägen, und dich für einen Ansatz entscheiden. Wir helfen dir dabei gerne, aber ein bißchen Eigeninitiative setzen wir voraus.

Christian

Weeks of programming can save you hours of planning

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

Ja natürlich.
Ich werde morgen Abend mal ein wenig tüffteln und bei Fragen melde ich mich nochmal - vorher werde ich natürlich eure Beiträge genau durchlesen.

Danke

4.939 Beiträge seit 2008
vor 8 Jahren

GetField ist nur ab .NET 4 verfügbar

Alle (wichtigen) Type-Methoden existieren schon seit .NET 2.0, auch Type.GetField()

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

GetField ist nur ab .NET 4 verfügbar
Alle (wichtigen) Type-Methoden existieren schon seit .NET 2.0, auch
>

In der Tat. Habe ich dann auch gesehen.

Ich habe nun folgenden Ansatz:


using UnityEngine;
using System.Collections;
using System;
using System.Reflection;

public static class SavegameManager // : MonoBehaviour
{
    public static void Add(System.Object pSystemObject)
    {
        Type type = pSystemObject.GetType();
        FieldInfo[] fields = type.GetFields();
        foreach (FieldInfo field in fields)
        {
            string fieldName = field.Name;
            object fieldValue = field.GetValue(field);
            Debug.Log(fieldName + " = " + fieldValue);
        }
    }

	public static void Add(UnityEngine.Object pUnityObject)
    {
        Type type = pUnityObject.GetType();
        FieldInfo[] fields = type.GetFields();
        foreach (FieldInfo field in fields)
        {
            string fieldName = field.Name;
            object fieldValue = field.GetValue(field);
            Debug.Log(fieldName + " = " + fieldValue);
        }
    }
     
    public static void Add(ScriptableObject pScriptableObject)
    {

    }

    public static void Save()
    {
        Add(new EarthSimilar());
        Add(PlayerController.selectedCharacter);
    }
}


Ich habe jedoch folgendes Problem:

FieldInfo[] fields = type.GetFields();

hat immer die Länge 0, also werden keine Felder gefunden.
Kann es damit zusammenhängen, dass meine Test-Objekte von anderen Klassen erben?

Bei Bedarf kann ich diese auch anfügen.

16.835 Beiträge seit 2008
vor 8 Jahren

Ist Dein Field überhaupt public, wie es laut Beschreibung von GetFields auch sein muss?
Eigenschaften statt Fields sind für Dich nichts? Generics mit Interfaces Constrants auch nichts?
Mir scheints hier noch ein paar Grundlagendefizite zu geben.

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

Ist Dein Field überhaupt public, wie es laut Beschreibung von GetFields auch sein muss?
Eigenschaften statt Fields sind für Dich nichts? Generics mit Interfaces Constrants auch nichts?
Mir scheints hier noch ein paar Grundlagendefizite zu geben.

Grundlagendefizite ist schon etwas arg heftig formuliert.

Ich habe mich evtl nicht genau ausgedrückt, könnte daran liegen.

Ich habe gefragt wie ich die Attribute einer Klasse auslesen kann und mir wurde gesagt, dass man diese Felder nennt.

Generics fällt raus, da unterschiedliche Objekte mit unterschiedlichen Eigenschaften speichern will. (Attribute war also nicht das richtige Wort)

Irgendwie finde ich den Unterschied zwischen Feld und Eigenschaft nicht.

Die Felder sind public:


public class CharStatSystem : MonoBehaviour
{
    //Eigenschaften
    //Standard-Eigenschaften
    public int ID {get; set;}
    public string nameItem { get; set; }
    public string description { get; set; }

    //Basis-Eigenschaften
    public float strength { get; set; }
    public float agility { get; set; }
    public float dexterity { get; set; }

    //Generierte-Eigenschaften
    public float lifepointsMax { get; set; } //ergibt sich aus Stärke(strength): Faktor ?
    public float lifepointsCurrent { get; set; } //ergibt sich aus lifepointsMax - Damage
    public float lifepointsRegeneration { get; set; } //ergibt sich aus Stärke(strength): Faktor ?
    public float damage { get; set; } //Klassenspezifisch
    public float armor { get; set; } //ergibt sich aus Stärke(strength): Faktor ?
    public float movementSpeed { get; set; } //ergibt sich aus Beweglichkeit(agility): Faktor ?
    public float movementSpeedMax { get; set; }
    public float maintaining { get; set; } //ergibt sich aus Geschicklichkeit(dexterity): Faktor ?

    //Zusätzliche-Eigenschaften
    public float experience { get; set; }
    public List<CharStatSystem> isUseableFrom { get; set; }
    //-> ABHÄNGIG von Gegenständen
    public CSSResistance resistance { get; set; } //Weitere Infos in der Basis-Resistenz-Klasse "CSSResistance"
    
...

4.939 Beiträge seit 2008
vor 8 Jahren

Hallo Ismoh,

also dein Code besteht aus Eigenschaften (properties), d.h. keinen Feldern (intern benutzt eine automatische Eigenschaft auch wieder ein sog. "backing field", aber daran kommt man nur, wenn man auch gezielt nach privaten Membern sucht). Du benötigst also GetProperties(), um die Eigenschaften auszulesen...

Du selber hast doch den Code mit "Eigenschaften" dokumentiert. Warum hast du dann nicht dieses Wort hier im Beitrag benutzt? So kommt es dann eben zu Verwirrung.

Ismoh Themenstarter:in
31 Beiträge seit 2010
vor 8 Jahren

Entschuldigt.

Habe währenddessen du den Beitrag erstellt hast, folgendes geändert:


public static void Add(UnityEngine.Object pUnityObject)
    {
        Type type = pUnityObject.GetType();
        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            string fieldName = property.Name;
            object fieldValue = property.GetValue(pUnityObject, null);
            Debug.Log(fieldName + " = " + fieldValue);
        }
    }

properties hat 34 Einträge.
Sollte also erstmal klappen.

Ich bedanke mich für die Unterstützung.