it-swarm.com.de

Abrufen von Feldern von GetType (). GetFields mit BindingFlag.Default

Ich benutze die Reflection-Klassen, um alle Felder in ein bestimmtes Objekt zu bekommen. Mein Problem ist jedoch, dass es perfekt funktioniert, wenn sich die Felder in einer normalen Klasse befinden, wie z.

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

Hier bekomme ich sowohl test1 als auch test2, mein Problem ist, dass ich Abstraktion und damit mehrere Klassen kombiniere.

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 starte, bekomme ich die Felder nicht von der GetType().GetFields(BindingFlag.Default) zurück.

Jedem dieser Felder ist auch eine Eigenschaft (get; set;) zugeordnet. Wenn ich den Code ausführe, bekomme ich die gesamten Eigenschaften von test1 zurück, nicht jedoch die tatsächlichen Felder.

Dies ist der Code, mit dem ich versuche, die Felder zu erhalten:

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 benutze 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 bekomme, aber nicht von den Feldern?

24
Patrick

Bearbeiten: Um private Mitglieder des Basistyps zu erhalten, müssen Sie:

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

Nochmal bearbeiten: Win.

Edit 22.03.13: Verwendet Concat anstelle von Union. Da wir BindingFlags.DeclaredOnly angeben und die Variable BaseType eines Typs nicht selbst gleich sein kann, 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));
}
47
Sam Harwell

Ein Typ, der einen anderen Typ erbt, kann keine privaten Teile dieses anderen Typs sehen, er kann geschützte, interne und öffentliche Teile sehen. Betrachten Sie den folgenden Code:

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 folgende:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

Der Typ A hat also zwei Felder. PrivateString und ProtectedString. Typ B hat einen; ProtectedString, die er von A erbt. Wenn Sie PrivateString durch den Typ B "erreichen" möchten, müssen Sie zu seinem Basistyp (b.GetType().BaseType) navigieren.

Beachten Sie jedoch, dass dieses Feld auch dann nicht in B deklariert wird, wenn der Typ ProtectedString ein Feld namens B meldet. es ist in A deklariert. Dies kann durch Hinzufügen von BindingFlags.DeclaredOnly zu den GetFields-Aufrufen im obigen Beispielprogramm untersucht werden. GetFields gibt keine Felder für B und zwei für A zurück.

In Ihr Codebeispiel übersetzt bedeutet dies, dass der Typ test3 nicht die Felder test2 und test3 enthält, da sie privat zum Typ test2 sind (die Ähnlichkeit der Feldnamen und Typnamen macht diesen Satz etwas verwirrend, ich habe Angst). ein

4
Fredrik Mörk

Sie können diese Erweiterungsmethode verwenden, um die Vererbungshierarchie eines Typs bis zum Objekt rekursiv zu durchlaufen und effektiv alle Felder des Typs und seine Vorfahren zurückzugeben:

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

(Nicht getestet, YMMV)

3
Jacob

Eigenschaften werden vererbt, Felder nicht. Geschützte Felder sind für untergeordnete Klassen sichtbar, werden jedoch nicht von ihnen übernommen. Mit anderen Worten, die abgeleitete Klasse hat zwar die Eigenschaften ihrer Basisklasse, sie kann jedoch nur die Felder sehen.

2
David M

Wenn Sie nur die Namen für Eigenschaften und Felder benötigen, verwenden Sie

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));
}
0
Carlo V. Dango

Aufzählung aller Typfelder einschließlich privater Mitglieder aus Basisklassen.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
0
Makeman