25

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

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)

抽象化されたクラスからプロパティを取得するが、フィールドからは取得しない理由はありますか?

4

6 に答える 6

54

編集:基本タイプのプライベートメンバーを取得するには、次のことを行う必要があります。

typeof(T).BaseType.GetFields(...)

もう一度編集:勝ちます。

2013年3月22日編集: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));
}
于 2009-07-20T19:47:08.833 に答える
4

A type that inherits another type cannot see private parts of that other type, it can see protected, internal and public parts. Consider the following code:

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

    }
}

The output of this program is the following:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

So, the type A has two fields; PrivateString and ProtectedString. Type B has one; ProtectedString, that it inherits from A. If you wish to "reach" PrivateString through the type B, you will need to navigate to its base type (b.GetType().BaseType).

Note though, that even if the type B reports to have a field called ProtectedString, this field is still not declared in B; it is declared in A. This can be examined by adding BindingFlags.DeclaredOnly to the GetFields calls in the above sample program; GetFields will return no fields for B, and two for A.

Translated to your code sample, this means that the type test3 does not contain the fields test2 and test3, since they are private to the type test2 (the similarity of the field names and type names make that sentence somewhat confusing, I am afraid).a

于 2009-07-20T20:01:31.973 に答える
3

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

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)

于 2009-07-20T20:09:58.837 に答える
2

プロパティは継承されますが、フィールドは継承されません。保護されたフィールドは子孫クラスに表示されますが、継承されません。つまり、子孫クラスには実際には基本クラスのプロパティがありますが、フィールドを表示することはできます。

于 2009-07-20T19:45:25.780 に答える
0

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

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));
}
于 2011-01-31T08:01:38.973 に答える
0

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

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
于 2017-07-03T21:02:40.993 に答える