未使用 BindingFlag.Default 从 GetType().GetFields 获取字段

发布于 2024-07-27 23:03:04 字数 1596 浏览 10 评论 0原文

我正在使用 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)

有什么想法为什么我从抽象类获取属性而不是字段?

I am using the Reflection classes in order to get all the fields inside a certain object.
My problem however is that it works perfectly when the fields are inside a normal class, like:

class test
{
   string test1 = string.Empty;
   string test2 = string.Empty;
}

Here i get both test1 and test2, my problem is that i use abstraction and thus several classes combined.

I got something like:

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

But when I run it, I don't get the fields back from the GetType().GetFields(BindingFlag.Default).

Everyone of those fields also have a property, get; set; attached to it.
When I run the code, I get the properties all the way back to test1 but not the actual fields.

This is the code that I'm trying to get the fields with:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)

I have also tried:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

I use the same code for the properties:

PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

foreach (PropertyInfo property in properties)

Any ideas why I get the properties from the abstracted classes but not the fields?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

鸢与 2024-08-03 23:03:04

编辑:要获取基本类型的私有成员,您必须:

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

再次编辑:Win。

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

Edit: To get private members of the base type, you have to:

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

Edit again: Win.

Edit 3/22/13: Used Concat instead of Union. Since we are specifying BindingFlags.DeclaredOnly and a type's BaseType cannot equal itself, Union is not needed and is more expensive.

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));
}
甜点 2024-08-03 23:03:04

继承另一个类型的类型无法看到该其他类型的私有部分,它可以看到受保护的、内部的和公共的部分。 考虑以下代码:

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 有两个字段; PrivateStringProtectedString。 类型 B 有一个; ProtectedString,它继承自A。 如果您希望通过类型 B“到达”PrivateString,则需要导航到其基本类型 (b.GetType().BaseType)。

但请注意,即使类型 B 报告有一个名为 ProtectedString 的字段,该字段仍然没有在 B 中声明; 它在 A 中声明。 可以通过将 BindingFlags.DeclaredOnly 添加到上述示例程序中的 GetFields 调用来检查这一点; GetFields 不会为 B 返回任何字段,为 A 返回两个字段。

转换为您的代码示例,这意味着类型 test3 不包含字段 test2test3,因为它们是类型 test3 私有的。 code>test2 (恐怕字段名称和类型名称的相似性使这句话有些混乱).a

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

沉默的熊 2024-08-03 23:03:04

您可以使用此扩展方法递归遍历类型的继承层次结构一直到对象,有效地返回该类型的所有字段及其所有祖先:(

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)

You can use this extension method to recursively traverse a type's inheritance hierarchy all the way up to object, effectively returning all fields of the type and all its ancestors:

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

(Untested, YMMV)

暮倦 2024-08-03 23:03:04

属性是继承的,而字段则不是。 受保护的字段对后代类可见,但不能被它们继承。 换句话说,后代类实际上具有其基类的属性,但它只是能够看到字段。

Properties are inherited, fields are not. Protected fields are visible to descendant classes, but not inherited by them. In other words, the descendant class actually has the properties of its base class, but it is just able to see the fields.

寂寞陪衬 2024-08-03 23:03:04

如果您只想要属性和字段的名称,请使用

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

If you just want the names for both properties and fields, use

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));
}
扛起拖把扫天下 2024-08-03 23:03:04

所有类型字段的枚举,包括基类中的私有成员。

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

Enumeration of all type fields including private members from base classes.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
时光清浅 2024-08-03 23:03:04

根据萨姆和史蒂夫的回答,这对我有用:


public static List<Variance> DetailedCompare<T>(this T val1, T val2)
    {
        try
        {
            List<Variance> variances = new List<Variance>();

            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
                                 BindingFlags.Static | BindingFlags.Instance |
                                 BindingFlags.DeclaredOnly;
            FieldInfo[] fi = val1.GetType().GetFields(flags);

            foreach (FieldInfo f in fi)
            {
                var previousValue = f.GetValue(val1);
                var newValue = f.GetValue(val2); 

                if (!Equals(previousValue, newValue))
                {
                    Variance v = new Variance
                    {
                        Prop = f.Name,
                        PreviousValue = previousValue,
                        NewValue = newValue
                    };
                    variances.Add(v);
                }
            }
            return variances;
        }
        catch
        {
            return null;
        }
    }

Based on Sam's and Steve's answers this is what it worked for me:


public static List<Variance> DetailedCompare<T>(this T val1, T val2)
    {
        try
        {
            List<Variance> variances = new List<Variance>();

            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
                                 BindingFlags.Static | BindingFlags.Instance |
                                 BindingFlags.DeclaredOnly;
            FieldInfo[] fi = val1.GetType().GetFields(flags);

            foreach (FieldInfo f in fi)
            {
                var previousValue = f.GetValue(val1);
                var newValue = f.GetValue(val2); 

                if (!Equals(previousValue, newValue))
                {
                    Variance v = new Variance
                    {
                        Prop = f.Name,
                        PreviousValue = previousValue,
                        NewValue = newValue
                    };
                    variances.Add(v);
                }
            }
            return variances;
        }
        catch
        {
            return null;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文