特定のオブジェクト内のすべてのフィールドを取得するために、リフレクションクラスを使用しています。しかし、私の問題は、フィールドが次のように通常のクラス内にあるときに完全に機能することです。
_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)
_
フィールドではなく抽象クラスからプロパティを取得する理由はありますか?
編集:基本タイプのprivateメンバーを取得するには、次の操作を行う必要があります。
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
で宣言されています。これは、上記のサンプルプログラムのGetFields
呼び出しにBindingFlags.DeclaredOnly
を追加することで確認できます。 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));
}
基本クラスのプライベートメンバーを含むすべての型フィールドの列挙体。
public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
type.BaseType?.EnumerateFields(flags)
.Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
type.EnumerateFields(flags);