Frage

Ich verwende die Reflection-Klassen, um alle Felder in einem bestimmten Objekt zu erhalten. Mein Problem ist jedoch, dass es funktioniert perfekt, wenn die Felder in einer normalen Klasse sind, wie:

class test
{
   string test1 = string.Empty;
   string test2 = string.Empty;
}

Hier i sowohl test1 und test2 bekommen, mein Problem ist, dass ich Abstraktion verwenden und somit mehr Klassen kombiniert werden.

Ich habe so etwas wie:

class test3 : test2
{
   string test4 = string.Empty;
   string test5 = string.Empty;
}

class test2 : test1
{
   string test2 = string.Empty;
   string test3 = string.Empty;
}
class test1
{
   string test0 = string.Empty;
   string test1 = string.Empty;
}

Aber wenn ich es laufen, ich habe nicht die Felder wieder aus dem GetType().GetFields(BindingFlag.Default).

Jeder dieser Felder haben eine Eigenschaft, get; set; attached to it. Wenn ich den Code ausführen, bekomme ich die Eigenschaften ganz nach test1 zurück, aber nicht die tatsächlichen Felder aus.

Dies ist der Code, dass ich versuche, die Felder zu bekommen:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)

Ich habe auch versucht:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

Ich verwende den gleichen Code für die Eigenschaften:

PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

foreach (PropertyInfo property in properties)

Irgendwelche Ideen, warum ich die Eigenschaften von den abstrahierten Klassen erhalten, aber nicht die Felder?

War es hilfreich?

Lösung

Edit: Um privat Mitglieder des Basistypen, müssen Sie:

typeof(T).BaseType.GetFields(...)

Bearbeiten wieder. Win

Bearbeiten 3/22/13: Gebrauchte Concat statt Union. Da wir BindingFlags.DeclaredOnly angeben und ein BaseType des Typs kann mich nicht gleich, wird Union nicht benötigt und ist teurer.

public static IEnumerable<FieldInfo> GetAllFields(Type t)
{
    if (t == null)
        return Enumerable.Empty<FieldInfo>();

    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | 
                         BindingFlags.Static | BindingFlags.Instance | 
                         BindingFlags.DeclaredOnly;
    return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
}

Andere Tipps

Ein Typ, der einen anderen Typ erbt nicht privaten Teile dieser anderen Art sehen, kann es geschützt, interne und öffentliche Teile sehen. Betrachten Sie den folgenden Code ein:

class A
{
    // note that this field is private
    string PrivateString = string.Empty;
    // protected field
    protected string ProtectedString = string.Empty;
}

class B : A { }

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("B Fields:");
        B b = new B();
        b.GetType()
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .ToList()
            .ForEach(f => Console.WriteLine(f.Name));

        Console.WriteLine("A Fields:");
        A a = new A();
        a.GetType()
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .ToList()
            .ForEach(f => Console.WriteLine(f.Name));

    }
}

Die Ausgabe dieses Programms ist die folgende:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

So hat der Typ A zwei Felder; PrivateString und ProtectedString. Typ B hat ein; ProtectedString, dass es erbt von A. Wenn Sie möchten PrivateString durch die Art B „erreichen“, müssen Sie dessen Basistyp (b.GetType().BaseType) navigieren.

Beachten Sie jedoch, dass, auch wenn die Art B Berichte ein Feld ProtectedString aufgerufen haben, wird dieses Feld noch nicht in B erklärt; es wird in A erklärt. Dies kann durch Hinzufügen zu den BindingFlags.DeclaredOnly GetFields Anrufen in dem obigen Beispielprogramm untersucht werden; GetFields kehrt keine Felder für B und zwei für A.

übersetzt auf Ihr Codebeispiel bedeutet dies, dass der Typ test3 enthält nicht die Felder test2 und test3, da sie privat auf die Art test2 (die Ähnlichkeit der Feldnamen und Typnamen sind, dass Satz etwas verwirrend, ich bin Angst) .a

Sie können mit dieser Erweiterung Methode verwenden, um rekursiv eine Vererbungshierarchie des Typs durchqueren den ganzen Weg bis zum Objekt, effektiv alle Felder des Typs zurückkehrt und alle seine Vorfahren:

public static class ReflectionExtensions
{
    public static IList<FieldInfo> GetAllFields(this Type type, BindingFlags flags)
    {
        if(type == typeof(Object)) return new List<FieldInfo>();

        var list = type.BaseType.GetAllFields(flags);
        // in order to avoid duplicates, force BindingFlags.DeclaredOnly
        list.AddRange(type.GetFields(flags | BindingFlags.DeclaredOnly));
        return list;
    }
}

(Ungeprüfte, YMMV)

Eigenschaften vererbt werden, Felder nicht. Geschützte Felder sind Klassen Nachkommen, aber nicht von ihnen geerbt. Mit anderen Worten hat die abgeleiteten Klasse tatsächlich die Eigenschaften seiner Basisklasse, aber es ist nur in der Lage, die Felder zu sehen.

Wenn Sie nur die Namen beider Objekte und Felder verwenden

private static IEnumerable<string > GetAllFieldsAndProperties(Type t)
{
  if (t == null)
    return Enumerable.Empty<string>();

  BindingFlags flags = BindingFlags.Public 
    | BindingFlags.NonPublic 
    | BindingFlags.Static 
    | BindingFlags.Instance 
    | BindingFlags.DeclaredOnly;
  return t.GetFields(flags).Select(x=>x.Name)
    .Union(GetAllFieldsAndProperties(t.BaseType))
    .Union(t.GetProperties(flags).Select(x=>x.Name));
}

Aufzählung aller Art Felder einschließlich privaten Mitglieder von Basisklassen.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top