【问题标题】:Reflection can't find private setter on property of abstract class反射在抽象类的属性上找不到私有设置器
【发布时间】:2013-12-24 16:12:21
【问题描述】:

当我在抽象类中有这个属性时:

public IList<Component> Components { get; private set; }

然后当我打电话时:

p.GetSetMethod(true)

p 是指向我的属性的 PropertyInfo 对象,我得到 null。

但是,如果我将属性设置器更改为受保护,我可以通过反射看到它。为什么是这样?我似乎不记得非抽象类有这个问题......

【问题讨论】:

  • 我不明白这如何适用于非抽象类的私有方法。你能提供一个SSCCE吗? sscce.org
  • GetSetMethod 的 true 参数应该是搜索非公共成员。
  • 奇怪,我相当肯定 GetSetMethod(true) 一直为我解析私有 set 访问器,但我不相信我已经使用它来解析基类上的成员。也许行为不一致。另外,您确定您的 PropertyInfo 指的是正确的属性,而不是隐藏您要查找的子类的属性吗?
  • 不,没有任何覆盖/隐藏属性...

标签: c# .net reflection


【解决方案1】:

我假设您正在从抽象类的派生类型的对象上调用它。该类根本没有属性设置器。它仅位于您的抽象基础上。这就是当您将其标记为protected 时它起作用的原因。在获取属性设置器时,您需要使用抽象类'Type

【讨论】:

  • 是的,我从派生类中调用它。这是有道理的,属性设置器不存在......
【解决方案2】:

这是一个旧线程,但我最近遇到了类似的问题,上述方法都不适合我。添加我的解决方案,因为它可能对其他人有用。

如前所述,如果属性的设置器是私有的,则它在继承的类中不存在。对我有用的是使用PropertyInfo 中的DeclaringType 降低一级

因此,使用 setter 检索属性的代码如下所示:

var propertyInfo = typeof(MyClass)
    .GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance)
    .DeclaringType
    .GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance);

在这种情况下,propertyInfo 包含 SetMethod 的值,因此您可以使用反射设置该值。

【讨论】:

  • 谢谢,效果很好。就我而言,我使用someType.GetProperty(name).DeclaringType.GetProperty(name).GetSetMethod(true) 来检索该方法。这更短并且有效,因为该属性是公共的,而它只是私有的 setter。我只是错过了DeclaringType
【解决方案3】:

在 C# 交互窗口中的一些简短实验表明,对于在类 A 上声明的属性 P,以下工作正常:

var p = typeof(A).GetProperty("P").GetSetMethod(true)

但是,一旦您尝试使用 A 的子类做同样的事情,GetSetMethod 就不再解析私有的 set 访问器:

// class B : A {}
var p = typeof(B).GetProperty("P").GetSetMethod(true) // produces 'null'.

换句话说,当反射类型与属性的声明类型相同时,您尝试的显然仅适用于 private 访问器。

【讨论】:

    【解决方案4】:

    诀窍是使用BindingFlags 枚举来指定您希望在获取PropertyInfo 对象时包含私有成员:

    PropertyInfo p = obj.GetType().GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance);
    

    【讨论】:

    • 这似乎不起作用 - 我仍然需要将属性设置器设置为受保护。我使用 GetProperties 枚举所有属性这一事实是否与此有关?
    • @ekolis 您还必须使用BindingFlags.FlattenHierarchy,因为您的属性位于基类中。
    • BindingFlags.FlattenHierarchy 仅适用于静态成员。
    • 这并不能解决他的问题。他可以解决财产;他无法解析set 访问器。问题在于所反映的类型:它必须是属性的声明类型。
    • @MikeStrobel 不,它没有。它还强制包含继承的成员。
    【解决方案5】:

    以下实验为我发现了这个问题。请注意,基类不必是 abstract 即可重现问题。

    public class Base
    {
        public string Something { get; private set; }
    }
    
    public class Derived : Base { }
    
    public class MiscTest
    {
        static void Main( string[] args )
        {
            var property1 = typeof( Derived ).GetProperty( "Something" );
            var setter1 = property1.SetMethod; //null
            var property2 = typeof( Base ).GetProperty( "Something" );
            var setter2 = property2.SetMethod; //non-null
    
            bool test1 = property1 == property2; //false
            bool test2 = property1.DeclaringType == property2.DeclaringType; //true
    
            var solution = property1.DeclaringType.GetProperty( property1.Name );
            var setter3 = solution.SetMethod; //non-null
            bool test3 = solution == property1; //false
            bool test4 = solution == property2; //true
            bool test5 = setter3 == setter2; //true
        }
    }
    

    我从中学到并发现令人惊讶的是,派生类型上的 PropertyInfo 与基类型上的 PropertyInfo 是不同的实例。奇怪!

    【讨论】:

      【解决方案6】:

      以@piotrwolkowski 的工作为基础

      var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
      var propertyInfo = typeof(MyClass).GetProperty("Components", flags);
      
      // only go to the declaring type if you need to
      if (!propertyInfo.CanWrite)
          propertyInfo = propertyInfo.DeclaringType.GetProperty("Components", flags);
      

      我在我的用例的绑定标志中添加了公共和非公共(这可能是多余的,我没有时间进一步研究)

      我正在设置一个从具有公共 get 和私有集的抽象基础继承的对象的实例

      再次感谢@piotrwolkowski

      【讨论】:

        猜你喜欢
        • 2018-07-25
        • 2012-05-10
        • 1970-01-01
        • 1970-01-01
        • 2011-11-03
        • 2010-12-06
        • 2010-12-14
        • 2012-03-02
        • 1970-01-01
        相关资源
        最近更新 更多