BindingFlag.Defaultではgettypeからフィールドを得ていない()。れるGetFields
-
18-09-2019 - |
質問
私は、特定のオブジェクト内のすべてのフィールドを取得するためにリフレクションクラスを使用しています。 私の問題は、しかし、フィールドは通常のクラスの中にあるとき、それは同じように、完全に動作することです。
class test
{
string test1 = string.Empty;
string test2 = string.Empty;
}
ここで私はTEST1とTEST2の両方を取得し、私の問題は、私は抽象化を使用するため、いくつかのクラスを組み合わせていることである。
私のような何かを得ました
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;
}
しかし、私はそれを実行したとき、私は戻ってGetType().GetFields(BindingFlag.Default)
からフィールドを得ることはありません。
これらのフィールドのみんなもそれに添付プロパティ、get; set;
を持っています。
私は、コードを実行すると、私はプロパティにすべてのバックTEST1への道ではなく、実際のフィールドを取得します。
これは、私がフィールドを取得しようとしているコードがあります
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)
私も試してみました。
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
私は、プロパティのために同じコードを使用します:
PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
foreach (PropertyInfo property in properties)
すべてのアイデアは、なぜ私は抽象化されたクラスではなく、フィールドからプロパティを取得する?
解決
編集:
:基本型ののプライベートのメンバーを取得するには、あなたがしなければなりませんtypeof(T).BaseType.GetFields(...)
編集再び:。勝利
編集3/22/13:使用Concat
の代わりUnion
。我々はBindingFlags.DeclaredOnly
を指定すると、型のBaseType
が自分自身を等しくすることはできませんので、Union
が必要とより高価であるされていません。
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));
}
他のヒント
別の型を継承するタイプは、それが保護され、内部および公共の部分を表示することができ、他のタイプのプライベートの部分を見ることができません。次のコードを考えてみます:
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));
}
}
このプログラムの出力は以下の通りです。
B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString
だから、型A
には2つのフィールドがあり、 PrivateString
とProtectedString
。タイプB
は1を持っています。 ProtectedString
は、それがA
から継承していること。あなたがタイプPrivateString
を通じてB
に「到達」したい場合は、その基本型(b.GetType().BaseType
)に移動する必要があります。
注しかし、型B
レポートはProtectedString
というフィールドを持っている場合でも、このフィールドはまだB
で宣言されていないこと。それはA
で宣言されています。これは、上記サンプルプログラムでBindingFlags.DeclaredOnly
呼び出しにGetFields
を添加することによって調べることができます。 GetFields
はB
、およびA
のための2つのために何のフィールドを返しません。
あなたのサンプルコードに変換、これはタイプtest3
は、私は、彼らはタイプtest2
(フィールド名とタイプ名の類似性にプライベートでその文はやや混乱しますので、フィールドは、test3
とtest2
含まれていないことを意味し恐れて).A
あなたは効果的にすべてのタイプのフィールドとそのすべての祖先を返すオブジェクトに再帰的にすべての方法アップ型の継承階層を横断するために、この拡張メソッドを使用することができます:
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;
}
}
(未テスト、YMMV)
のプロパティが継承され、フィールドではありません。保護されたフィールドは、下位クラスに表示されますが、それらによって継承されません。言い換えれば、子孫のクラスは、実際には、その基本クラスのプロパティを持っていますが、それだけでフィールドを参照することができます。
あなただけのプロパティとフィールドの両方の名前をしたい場合は、使用します。
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ます。
public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
type.BaseType?.EnumerateFields(flags)
.Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
type.EnumerateFields(flags);