Problems with accessing protected static List using Reflection - c#

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;

Related

How get private properties of Class/BaseClass?

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

Get only protected members via .net reflection

This returns all non-public instance properties:
var instanceNonPublic = currentType.GetProperties (BindingFlags.Instance |
BindingFlags.NonPublic);
But is there any way to determine which access modifier applies to each property? private, internal or protected?
Since properties are made of get method and set method you can iterate them and filter the relevant PropertyInfos using their get and set methods' access modifiers:
var instancePrivate = currentType.GetProperties(BindingFlags.Instance |
BindingFlags.NonPublic)
.Where(x => x.GetMethod.IsPrivate &&
x.SetMethod.IsPrivate);
Those are the interesting access modifiers:
IsPrivate indicates that the method is private.
IsFamily indicates that the method is protected.
IsAssembly indicates that the method is internal.
Other way to elegantly set the filter is using FindMembers:
public void YourMethod()
{
...
var instancePrivate = currentType.FindMembers(MemberTypes.Property,
BindingFlags.Instance |
BindingFlags.NonPublic,
PrivateMemberFilter, null);
.OfType<PropertyInfo>();
...
}
static readonly MemberFilter PrivatePropertyFilter = (objMemberInfo, objSearch) =>
{
PropertyInfo info = (objMemberInfo as PropertyInfo);
if (info == null)
{
return false;
}
return info.GetMethod.IsPrivate && info.SetMethod.IsPrivate;
};

Get private property of a private property using reflection

public class Foo
{
private Bar FooBar {get;set;}
private class Bar
{
private string Str {get;set;}
public Bar() {Str = "some value";}
}
}
If I've got something like the above and I have a reference to Foo, how can I use reflection to get the value Str out Foo's FooBar? I know there's no actual reason to ever do something like this (or very very few ways), but I figure there has to be a way to do it and I can't figure out how to accomplish it.
edited because I asked the wrong question in the body that differs from the correct question in the title
You can use the GetProperty method along with the NonPublic and Instance binding flags.
Assuming you have an instance of Foo, f:
PropertyInfo prop =
typeof(Foo).GetProperty("FooBar", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo getter = prop.GetGetMethod(nonPublic: true);
object bar = getter.Invoke(f, null);
Update:
If you want to access the Str property, just do the same thing on the bar object that's retrieved:
PropertyInfo strProperty =
bar.GetType().GetProperty("Str", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo strGetter = strProperty.GetGetMethod(nonPublic: true);
string val = (string)strGetter.Invoke(bar, null);
There is a way to slightly simplify Andrew's answer.
Replace the calls to GetGetMethod() + Invoke() with a single call to GetValue() :
PropertyInfo barGetter =
typeof(Foo).GetProperty("FooBar", BindingFlags.NonPublic | BindingFlags.Instance);
object bar = barGetter.GetValue(f);
PropertyInfo strGetter =
bar.GetType().GetProperty("Str", BindingFlags.NonPublic | BindingFlags.Instance);
string val = (string)strGetter.GetValue(bar);
I did some testing, and I didn't find a difference, then I found this answer, which says that GetValue() calls GetGetMethod() with error checking, so there is no practical difference (unless you worry about performance, but when using Reflection I guess that you won't).

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.

Use reflection to find the name of a delegate field

Let's say that I have the following delegate:
public delegate void Example();
and a class such as the following:
public class TestClass {
Example FailingTest = () => Assert.Equal(0,1);
}
How can I use reflection to get the name "FailingTest"?
So far I have tried:
var possibleFields = typeof(TestClass).GetFields(relevant_binding_flags)
.Where(x => x.FieldType.Equals(typeof(Example)));
foreach(FieldInfo oneField in possibleFields) {
// HERE I am able to access the declaring type name
var className = oneField.ReflectedType.Name; // == "TestClass"
// but I am not able to access the field
// name "FailingTest" because:
var fieldName = oneField.Name; // == "CS$<>9__CachedAnonymousMethodDelegate1"
}
Stepping through in the debugger, I am unable to find a path to the name of the declared field, "FailingTest".
Is that info retained at runtime or is it lost when the anonymous delegate is assigned?
What BindingFlags are you passing to GetFields? I used these:
BindingFlags.NonPublic | BindingFlags.Instance
and I was able to see the name of the field.

Categories