Question

J'utilise les classes de réflexion afin d'obtenir tous les champs à l'intérieur d'un certain objet. Mon problème est cependant que cela fonctionne parfaitement lorsque les champs sont à l'intérieur d'une classe normale, comme:

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

Ici, je reçois à la fois test1 et test2, mon problème est que j'utilise l'abstraction et donc plusieurs classes combinées.

Je suis quelque chose comme:

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

Mais quand je le lance, je ne reçois pas les champs arrière de la GetType().GetFields(BindingFlag.Default).

Chacun de ces domaines ont également une propriété, get; set; attaché. Quand je lance le code, je reçois les propriétés tout le chemin du retour à test1 mais pas les champs réels.

Voici le code que je suis en train d'obtenir les champs avec:

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

J'ai aussi essayé:

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

J'utilise le même code pour les propriétés:

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

foreach (PropertyInfo property in properties)

Toutes les idées pourquoi je reçois les propriétés des classes abstraites, mais pas les champs?

Était-ce utile?

La solution

Edit: Pour obtenir privé membres du type de base, vous devez:

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

Modifier à nouveau. Win

Modifier 22/03/13: Concat Utilisé au lieu de Union. Puisque nous spécifions BindingFlags.DeclaredOnly et la BaseType d'un type ne peut pas lui-même égal, Union n'est pas nécessaire et est plus cher.

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

Autres conseils

Un type qui hérite d'un autre type ne peut pas voir les parties intimes de cet autre type, il peut voir protégé, les parties internes et publiques. Considérez le code suivant:

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

    }
}

La sortie de ce programme est le suivant:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

Ainsi, le type A a deux champs; PrivateString et ProtectedString. Type B a un; ProtectedString, qu'il hérite de A. Si vous souhaitez « atteindre » PrivateString à travers le B de type, vous devez accéder à son type de base (b.GetType().BaseType).

Notez cependant que même si les rapports de B type d'avoir un champ appelé ProtectedString, ce champ est toujours pas déclaré dans B; il est déclaré dans A. Cela peut être examiné en ajoutant BindingFlags.DeclaredOnly aux appels GetFields dans le programme ci-dessus de l'échantillon; GetFields retournera pas de champs pour B, et deux pour A.

Traduit à votre exemple de code, cela signifie que le type test3 ne contient pas les champs test2 et test3, car ils sont privés du test2 de type (la similitude des noms de champs et les noms de type font cette phrase un peu confus, je suis peur) .a

Vous pouvez utiliser cette méthode d'extension pour traverser récursive la hiérarchie d'héritage d'un type tout le chemin jusqu'à l'objet, retourner efficacement tous les champs du type et tous ses ancêtres:

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

(Untested, YMMV)

Les propriétés sont héritées, les champs ne sont pas. Les champs protégés sont visibles pour les classes dérivées, mais pas hérité par eux. En d'autres termes, la classe descendante possède effectivement les propriétés de sa classe de base, mais il est juste capable de voir les champs.

Si vous voulez juste les noms pour les propriétés et les champs, utilisez

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

Enumeration de tous les champs de type y compris les membres privés de classes de base.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top