J'utilise les classes de réflexion pour obtenir tous les champs d'un objet. Cependant, mon problème est qu'il 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, j'obtiens à la fois test1 et test2, mon problème est que j'utilise l'abstraction et donc plusieurs classes combinées.
J'ai 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 récupère pas les champs de la GetType().GetFields(BindingFlag.Default)
.
Chacun de ces champs est également associé à une propriété, get; set;
. Lorsque je lance le code, je récupère toutes les propriétés dans Test1, mais pas les champs réels.
C'est le code que j'essaie d'obtenir dans les champs:
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)
Des idées pour lesquelles je récupère les propriétés des classes abstraites mais pas des champs?
Edit: Pour obtenir private membres du type de base, vous devez:
typeof(T).BaseType.GetFields(...)
Modifier à nouveau: Win.
Éditer 22/03/13: utilisé Concat
au lieu de Union
. Puisque nous spécifions BindingFlags.DeclaredOnly
et que la variable BaseType
d'un type ne peut pas être identique à elle-même, Union
n'est pas nécessaire et coûte 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));
}
Un type qui hérite d'un autre type ne peut pas voir les parties privées de cet autre type, il peut voir les parties protégées, internes et publiques. Considérons 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 la suivante:
B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString
Donc, le type A
a deux champs; PrivateString
et ProtectedString
. Le type B
en a un; ProtectedString
, qu'il hérite de A
. Si vous souhaitez "atteindre" PrivateString
par le type B
, vous devrez accéder à son type de base (b.GetType().BaseType
).
Notez cependant que même si le type B
indique avoir un champ appelé ProtectedString
, ce champ n'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 l'exemple de programme ci-dessus; GetFields
ne renverra aucun champ pour B
et deux pour A
.
Traduit en exemple de code, cela signifie que le type test3
ne contient pas les champs test2
et test3
, car ils sont privés du type test2
(la similarité des noms de champs et des noms de types rend cette phrase quelque peu déroutante, je le crains). une
Vous pouvez utiliser cette méthode d'extension pour parcourir de manière récursive la hiérarchie d'héritage d'un type jusqu'à l'objet, renvoyant ainsi 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;
}
}
(Non testé, YMMV)
Les propriétés sont héritées, les champs ne le sont pas. Les champs protégés sont visibles pour les classes descendantes, mais ne les héritent pas. En d'autres termes, la classe descendante a les propriétés de sa classe de base, mais elle est simplement capable de voir les champs.
Si vous voulez juste les noms des propriétés et des 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));
}
Énumération de tous les champs types, y compris les membres privés des 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);