How get private properties of Class/BaseClass? - c#

I use this code:
BindingFlags flags= BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
PropertyInfo prop = myObj.GetProperty("Age", flags);
prop is not null. However, when I try to get all properties from myObj:
foreach(MemberInfo e in myObj.GetType().GetMembers( flags) ) { //neither GetProperties helps
Console.WriteLine(e.Name);
}
that property (Age) is not listed. I can't understand how this happens.

The dfiference between Type.GetProperty and Type.GetMembers is that both return private properties/members(which include properties), but GetMembers only of this type and not from base types whereas GetProperty also returns private properties of base types.
GetProperty:
Specify BindingFlags.NonPublic to include non-public properties (that
is, private, internal, and protected properties) in the search.
GetMembers:
Specify BindingFlags.NonPublic to include non-public members (that is,
private, internal, and protected members) in the search. Only
protected and internal members on base classes are returned; private
members on base classes are not returned.
So i guess that Age is an inherited property. If you would add BindingFlags.DeclaredOnly the result should be the same, you wouldn't see Age.
If you want to force GetMembers to include also private members of base types, use following extension method that loops all base types:
public static class TypeExtensions
{
public static MemberInfo[] GetMembersInclPrivateBase(this Type t, BindingFlags flags)
{
var memberList = new List<MemberInfo>();
memberList.AddRange(t.GetMembers(flags));
Type currentType = t;
while((currentType = currentType.BaseType) != null)
memberList.AddRange(currentType.GetMembers(flags));
return memberList.ToArray();
}
}
Now your BindingFlags work already and even a private "inherited" Age property is returned:
MemberInfo[] allMembers = myObj.GetType().GetMembersInclPrivateBase(flags);

Related

Problems with accessing protected static List using Reflection

I'm trying to mod Planetbase and I have to access protected static List<Character> mCharacters = new List<Character>(); inside public abstract class Character in Planetbase namespace. Here is my code:
FieldInfo characters = typeof(Character).GetField("mCharacters", BindingFlags.NonPublic | BindingFlags.Instance);
carriedResources = Character.characters.Where(x => x.getLoadedResource() != null)
.ToDictionary(y => y, x => x.getLoadedResource()); // Get all carried resources across all characters
However I'm getting the "Character does not contain the definition for characters" error despite writing a method to access it. No idea what I'm doing wrong.
The BindingFlags you are using are not correct. What you need is BindingFlags.NonPublic | BindingFlags.Static. You can find out more about this enumeration here.
These are some of the most used binding flags when one would search for any type member (field, property, method, etc.):
BindingFlags.Public specifies that public members are to be included in the search.
BindingFlags.NonPublic specifies that non-public members are to be included in the search.
BindingFlags.Instance specifies that instance members are to be included in the search.
BindingFlags.Static specifies that static members are to be included in the search.
Update:
I just noticed that you are not accessing the field information appropriately. After you have the field info, you can access the underlying value like this:
FieldInfo field = typeof(Character).GetField("mCharacters", BindingFlags.NonPublic | BindingFlags.Instance);
var value = field.GetValue(__character_instance__);
The retrieved value will be of type object so you have to safely convert it to the appropriate type.
So if I have this class:
public class Person
{
private readonly string _name;
public Person(string name)
{
this._name = name;
}
}
I can access the field data like this:
var person = new Person("Tony Troeff");
var field = typeof(Person).GetField("_name", BindingFlags.NonPublic | BindingFlags.Instance);
var fieldValue = field.GetValue(person) as string;

GetRuntimeProperties instead of GetProperty

I need to find property inside of generic type. This is an old way (and since my code is dedicated for WinRT I believe I need another approach):
PropertyInfo pi = typeof(TRp).GenericTypeArguments[0].GetProperty(idField, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
I need to achieve the same result using GetRuntimeProperties. This is my approach:
PropertyInfo pi = typeof(TRp).GenericTypeArguments[0].GetRuntimeProperties().Single(p => p.Name.ToUpper() == idField.ToUpper()...
as you can see I implemented IgnoreCase in a custom way, probably it can be done better?
How can I implement remaining BindingFlags?
Thank you!
You actually dont need to. This is how Type.GetRuntimeProperties is implemented:
public static IEnumerable<PropertyInfo> GetRuntimeProperties(this Type type)
{
CheckAndThrow(type);
IEnumerable<PropertyInfo> properties = type.GetProperties(everything);
return properties;
}
Where everything is defined as following:
private const BindingFlags everything = BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Static;
Which means it will already look for your required flags.
Edit:
If you want to specify BindingFlags yourself, you can write your own custom extension method:
public static class TypeExtensions
{
public static IEnumerable<PropertyInfo> GetAllProperties(this TypeInfo type,
BindingFlags bindingFlags)
{
var propertyInfos = type.GetProperties(bindingFlags);
var subtype = type.BaseType;
if (subtype != null)
list.AddRange(subtype.GetTypeInfo().GetAllProperties(bindingFlags));
return propertyInfos.ToArray();
}
}
Note this hasn't been tested. It is merely an attempt to show you that you can do it yourself.

Get all properties of current class and base class

I have 2 classes (lets say "BaseItem" and "ChildItem") with several internal properties. In the BaseClass i have defined a method which should read out all of this properties with
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
or
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this.GetType());
When i call this method in an instance of "ChildItem", i get only the properties that are defined in "ChildItem". What can i do to get also the the properties of "BaseItem"?
Regards
Dave
For internal properties (as clarified in the question comments), although not indicated (they're internal for a reason), you can use:
var internalProperties = GetType().GetProperties(
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public));
It's the flag BindingFlags.NonPublic that needs to be applied.
You could just cast it to BaseItem and do GetProperties() separately..

GetMethod returning null

I have an asp.net web page. This is the class implementing the page:
public partial class _Default : System.Web.UI.Page
{
private readonly string delegateName = "DynamicHandler";
protected void Page_Load(object sender, EventArgs e)
{
EventInfo evClick = btnTest.GetType().GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;
MethodInfo method = this.GetType().GetMethod("DynamicHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
Delegate d = Delegate.CreateDelegate(tDelegate, this, method);
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(btnTest, addHandlerArgs);
}
private void DynamicHandler(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
I am trying to hook up an event handler dynamicly. For some reason method remains null and I can't figure out why. I have done this many times before and I can't figure out what I'm missing.
EDIT: I found that this.GetType() returns the type of the page ASP.default_aspx and not the actual type implementing the page. I don't really know how to get around this...
For the benefit of anyone else, GetMethod() can also return null if the arguments you passed do not match the arguments of the method you are trying to find. So, for example, if you are trying to find the method:
SomeMethod(int intParam, string stringParam)
You need to pass the parameter types to GetMethod:
type.GetMethod("SomeMethod", new[] { typeof(int), typeof(string) });
Or, if you want to specify special binding flags:
type.GetMethod("SomeMethod", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(int), typeof(string) }, null);
As you've discovered in your edit, the actually ASPX page gets compiled into a class that inherits from _Default (where your code is located). So you need to make DynamicHandler (at least) protected rather than private.
Specify BindingFlags.FlattenHierarchy also:
this.GetType().GetMethod("DynamicHandler",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
There are two things to be aware of.
(1) When you use:
this.GetType()
or equivalently just GetType(), the type which is returned is the actual run-time type of the actual instance. Since _Default is a non-sealed class, that type might very well be a more derived (more specialized type) than _Default, i.e. some class which has _Default as its direct or indirect base class.
If what you want is always the "constant" type _Default, use the typeof keyword, so use:
typeof(_Default)
instead of GetType(). This alone would solve your problem.
(2) Even if you specify BindingFlags.NonPublic, inherited private members are not returned. With your choice of binding flags, private methods declared in the same class (the derived class) are returned, but private methods inherited from base classes are not returned. However with internal and protected members, both the ones declared in the class itself and the ones declared in the base classes are returned.
This might make some sense, since a private method is not meant to be invoked from a derived class.
Changing the access level of your DynamicHandler method from private to e.g. protected (as suggested in the other answer) would be enough to solve your problem, as inherited protected members are selected when you use BindingFlags.NonPublic.
It is still interesting that you can't get the inherited private members with BindingFlags. Related thread C#: Accessing Inherited Private Instance Members Through Reflection. It is possible to write a method that searches all base types, of course, like:
static MethodInfo GetPrivateMethod(Type type, string name)
{
MethodInfo retVal;
do
{
retVal = type.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (retVal != (object)null)
break;
type = type.BaseType;
} while (type != (object)null);
return retVal;
}
That alone would also have solved your problem.

GetFields of derived type

I am trying to reflect the fields in a derived type but it's returning the fields of the
base type.
public class basetype
{
string basevar;
}
public class derivedtype : basetype
{
string derivedvar;
}
In some function:
derivedtype derived = new derivedtype();
FieldInfo[] fields = derived.GetType().GetFields();
This will return basevar, but not derivedvar. I've tried all the different bindings and it doesn't seem to make a difference.
Also, I'm doing this in ASP.NET within App_Code where basevar is defined in App_Code and derivedvar is a user control defined in App_Controls where the types are not in scope.
As is, this will return nothing as the default binding is for public fields only.
As is also, derivedtype isn't derived from basetype
With:
FieldInfo[] fields = derived.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
It returns derivedvar. I've just checked in LINQPad.
If I change derivedtype to be derived from basetype, then I can get both fields with:
FieldInfo[] fields = derived.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Concat(derived.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)).ToArray();
Reflection is a bit odd.
If the members are public, all of them up the entire hierarchy are visible.
If the members are non-public, you have to specify BindingFlags.NonPublic and you will only get those members that are of the type used. Inherited members are not visible. If you want to see all the non-public members of a type you'll have to walk up the inheritence chain.

Categories