web-dev-qa-db-ja.com

BindingFlag.Defaultを使用してGetType()。GetFieldsからフィールドを取得しない

特定のオブジェクト内のすべてのフィールドを取得するために、リフレクションクラスを使用しています。しかし、私の問題は、フィールドが次のように通常のクラス内にあるときに完全に機能することです。

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

フィールドではなく抽象クラスからプロパティを取得する理由はありますか?

25
Patrick

編集:基本タイプの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));
}
50
Sam Harwell

別の型を継承する型は、その別の型のプライベート部分を見ることができず、保護された内部部分とパブリック部分を見ることができます。次のコードを検討してください。

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)に移動する必要があります。

ただし、タイプBProtectedStringと呼ばれるフィールドを持つと報告した場合でも、このフィールドはBで宣言されていません。 Aで宣言されています。これは、上記のサンプルプログラムのGetFields呼び出しにBindingFlags.DeclaredOnlyを追加することで確認できます。 GetFieldsは、Bのフィールドを返さず、Aのフィールドを2つ返します。

コードサンプルに変換すると、これは、タイプtest3にフィールドtest2test3が含まれていないことを意味します。これらはタイプtest2に対してプライベートであるためです(フィールド名とタイプ名の類似性により、この文はやや混乱しますが、心配です)。 a

4
Fredrik Mörk

この拡張メソッドを使用して、型の継承階層をオブジェクトまで再帰的にたどることができ、型のすべてのフィールドとそのすべての祖先を効果的に返します。

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)

3
Jacob

プロパティは継承されますが、フィールドは継承されません。プロテクトフィールドは、子孫クラスに表示されますが、継承されません。言い換えると、子孫クラスには実際にはその基本クラスのプロパティがありますが、フィールドを表示するだけです。

2
David M

プロパティとフィールドの両方の名前だけが必要な場合は、

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));
}
0
Carlo V. Dango

基本クラスのプライベートメンバーを含むすべての型フィールドの列挙体。

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
0
Makeman