BindingFlag.Defaultではgettypeからフィールドを得ていない()。れるGetFields

StackOverflow https://stackoverflow.com/questions/1155529

  •  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つのフィールドがあり、 PrivateStringProtectedString。タイプBは1を持っています。 ProtectedStringは、それがAから継承していること。あなたがタイプPrivateStringを通じてBに「到達」したい場合は、その基本型(b.GetType().BaseType)に移動する必要があります。

注しかし、型BレポートはProtectedStringというフィールドを持っている場合でも、このフィールドはまだBで宣言されていないこと。それはAで宣言されています。これは、上記サンプルプログラムでBindingFlags.DeclaredOnly呼び出しにGetFieldsを添加することによって調べることができます。 GetFieldsB、およびAのための2つのために何のフィールドを返しません。

あなたのサンプルコードに変換、これはタイプtest3は、私は、彼らはタイプtest2(フィールド名とタイプ名の類似性にプライベートでその文はやや混乱しますので、フィールドは、test3test2含まれていないことを意味し恐れて).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);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top