可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
When I have this property in an abstract class:
public IList<Component> Components { get; private set; }
Then when I call:
p.GetSetMethod(true)
with p being a PropertyInfo object pointing to my property, I get null.
However if I change the property setter to protected, I can see it via reflection. Why is this? I don't seem to recall having this problem with non-abstract classes...
回答1:
I assume you are calling this on an object from a derived type of your abstract class. There isn't a property setter at all on that class. It is only located on your abstract base. This is why it works when you mark it as protected
. You need use your abstract class' Type
instead when getting the property setter.
回答2:
It's an old thread but I run into similar issue recently and none of the above worked for me. Adding my solution as it may be useful for others.
As said before if the setter of a property is private it does not exist in the inherited class. What worked for me was to go one level lower using DeclaringType
of the PropertyInfo
So the code to retrieve the property with the setter would look like this:
var propertyInfo = typeof(MyClass)
.GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance)
.DeclaringType
.GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance);
In this case the propertyInfo
contains a value for SetMethod
so you can set the value using reflection.
回答3:
Some brief experimentation in the C# Interactive window suggests that for a property P
declared on a class A
, the following works just fine:
var p = typeof(A).GetProperty("P").GetSetMethod(true)
But as soon as you attempt the same thing with a subclass of A
, GetSetMethod
no longer resolves the private set
accessor:
// class B : A {}
var p = typeof(B).GetProperty("P").GetSetMethod(true) // produces 'null'.
In other words, what you attempted apparently only works for private
accessors when the reflected type is the same as the property's declaring type.
回答4:
The trick is to use the BindingFlags enumeration to specify that you want private members to be included when you obtain the PropertyInfo
object:
PropertyInfo p = obj.GetType().GetProperty("Components", BindingFlags.NonPublic | BindingFlags.Instance);
回答5:
To build on the work of @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);
I added both public and non-public to the binding flags for my use case (it may be overkill and I don't have the time to pursue it further)
I was setting the instance of an object that inherited from an abstract base with public get and private set
Again, all credit to @piotrwolkowski
回答6:
The following experimentation uncovered the issue for me. Note that the base class doesn't have to be abstract
to reproduce the problem.
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
}
}
What I learned from this and found surprising, is that the PropertyInfo
on the derived type is a different instance than the PropertyInfo
on the base type. Weird!