【问题标题】:type.FindMembers missing inherited private members with binding flagstype.FindMembers 缺少带有绑定标志的继承私有成员
【发布时间】:2015-12-04 19:48:49
【问题描述】:

编辑:我的单元测试出错了。所以我的问题是无效的。我在下面标记了正确的答案,问题应该是“如何在继承的类上获取私有成员”。

我遍历类层次结构来获取我需要的私有成员。

我正在使用反射来获取类层次结构的成员。最初,我是分别提取属性和字段。我重构了我的代码只是为了得到MemberInfo 并开始遇到一个小问题。

最初我能够使用以下方法获取所有字段:

type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic)

这将返回类层次结构中的所有公共和私有字段。 例如关于类:

     class ViewModel {

            [MetaData("MetaFieldType1", typeof(Parent), null)]
            public string field1;

            [MetaData("MetaFieldType2", typeof(Parent), "Field Value 2")]
            private string field2;

            [MetaData("MetaProtectedField", typeof(Parent), "Protected Field")]
            protected string pField;

            protected string pField2;

            [MetaData("MetaType 1", typeof(Parent), null)]
            public String Prop1 { get; set; }
            [MetaData("MetaType 2", typeof(Parent), "The Value")]
            public String Prop2 { get; set; }

            public string Field2 { get { return field2; } set { field2 = value; } }
        }

        class ViewModel2 : ViewModel {

            public string PField { get { return pField; } set { pField = value; } }

            [MetaData("MetaProtectedField2", typeof(Parent), null)]
            public string PField2 { get { return pField2; } set { pField2 = value; } }
        }

ViewModelViewModel2 都会返回 4 个字段

然后我更改了要使用的代码(而不是获取属性然后字段):

type.FindMembers(MemberTypes.Field | MemberTypes.Property,
                BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic,
                allMemberFilter,null)

在哪里

protected static readonly MemberFilter allMemberFilter = new MemberFilter(
            delegate (MemberInfo objMemberInfo, Object objSearch) {
                return true;
            });

ViewModel 返回所有属性和字段;但是,ViewModel2 缺少在ViewModel 中找到的私有字段(即field2)。在使用具有相同绑定标志的GetFieldsGetProperties 时,情况并非如此。

如果我将field2 更改为受保护,则它会显示在搜索中。

这是框架的问题还是我遗漏了什么?

【问题讨论】:

  • 我不知道memberfield的确切定义,但我很确定基类的私有field不是继承的member类。
  • 您确定typeof (ViewModel2).GetFields(... 返回4 件商品吗?我对此进行了测试,它返回了 3 个项目。
  • @YacoubMassad 你是对的,我的单元测试中有一个错误给了我这个错误。如果我想要继承类的私有成员,我将不得不遍历类层次结构。

标签: c# .net


【解决方案1】:

首先,基Type 的私有成员被认为是继承Type 的成员。来自C# 语言规范版本 5.0

类继承其基类的成员。继承意味着一个类隐式包含其基类的所有成员 (A.k.a:包括基类的私有成员),除了实例和静态构造函数,以及基类的析构函数。

如果您查看BindingFlags.FlattenHierarchy 文档,您会发现它仅指static 成员:

指定应返回层次结构上的公共和受保护静态成员。

话虽如此,显然但不幸的是,获得Type 成员的private 成员的唯一方法是对他们声明的Type 使用反射,在我们的例子中,这意味着基础Type 本身。

所以我们必须编写一个扩展来递归地这样做:

static class TypeExtensions
{
    public static IEnumerable<MemberInfo> GetAllInstanceMembers(this Type type)
    {
        if (type == null || type == typeof (object) || !type.IsClass || type.IsInterface)
        {
            return Enumerable.Empty<MemberInfo>();
        }

        IEnumerable<MemberInfo> baseMembers = type.BaseType.GetAllInstanceMembers();

        IEnumerable<MemberInfo> interfacesMembers = type.GetInterfaces().SelectMany(x => x.GetAllInstanceMembers());

        IEnumerable<MemberInfo> currentMembers = type.FindMembers(MemberTypes.Field | MemberTypes.Property,
            BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic,
            AllMemberFilter, null);

        return baseMembers.Concat(interfacesMembers).Concat(currentMembers);
    }

    static readonly MemberFilter AllMemberFilter = (objMemberInfo, objSearch) => true;
}

请注意,显然BindingFlags.DeclaredOnly 使该方法返回 auto-properties 的构造函数生成的 支持字段,而在问题的示例中它们没有返回,这可以通过将return 行更改为:

return baseMembers.Concat(interfacesMembers).Concat(currentMembers)
    .Where(x => x.GetCustomAttribute<CompilerGeneratedAttribute>() == null);

另外,我必须说,GetMembersFindMembersGetProperties/GetFields 得到了相同的结果

【讨论】:

  • 在我的单元测试中发现错误后,我想出了一个类似的解决方案。我使用原始查询来获取类型中我需要的所有公共/私有/受保护成员。然后我在对象上递归调用 type.BaseType ,直到它是对象的实例来获取我需要的私有字段。对于我的实际用例,我永远不会真正期望必须这样做。所以我用一个单独的方法来处理那些罕见的情况。
  • 投反对票的人请详细说明,以便我改进答案。
猜你喜欢
  • 2016-07-15
  • 2020-09-04
  • 2020-09-01
  • 2018-05-11
  • 2011-09-26
  • 2013-02-12
  • 2015-01-21
  • 2011-02-10
相关资源
最近更新 更多