Get all base property declarations within a class hierarchy - c#

Consider this interesting set of types:
class A { public virtual int MyProperty { get; set; } }
class B : A { public override int MyProperty { get; set; } }
class C : B { public new virtual int MyProperty { get; set; } }
class D : C { public override int MyProperty { get; set; } }
class E : D { public new int MyProperty { get; set; } }
I see three different properties here, with five implementations hiding or overriding each other.
I'm trying to get the set of property declarations for type E:
A.MyProperty
C.MyProperty
E.MyProperty
But my code below gives me the set of property implementations:
A.MyProperty
B.MyProperty
C.MyProperty
D.MyProperty
E.MyProperty
What do I need to do to get the property declarations?
Or is there any chance that B.MyProperty will ever return a value other than A.MyProperty for any instance of E?
If my approach is heading in the wrong direction: How do I get all property members of a type including any hidden ones, but not including those that will never have different values?
void GetProperties(Type type)
{
if (type.BaseType != null)
{
GetProperties(type.BaseType);
}
foreach (var item in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("{0}.{1}", type.Name, item.Name);
}
}
Desired outputs:
typeof(A) typeof(B) typeof(C) typeof(D) typeof(E)
------------ ------------ ------------ ------------ ------------
A.MyProperty A.MyProperty A.MyProperty A.MyProperty A.MyProperty
C.MyProperty C.MyProperty C.MyProperty
E.MyProperty

This may get you started down the path that you want:
static void GetProperties(Type type)
{
if (type.BaseType != null)
{
GetProperties(type.BaseType);
}
foreach (var item in type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public))
{
MethodInfo method = item.GetGetMethod();
MethodInfo baseMethod = method.GetBaseDefinition();
System.Diagnostics.Debug.WriteLine(string.Format("{0} {1}.{2} {3}.{4}", type.Name, method.DeclaringType.Name, method.Name, baseMethod.DeclaringType, baseMethod.Name));
if (baseMethod.DeclaringType == type)
{
Console.WriteLine("{0} {1}", type.Name, item.Name);
}
}
}
This code outputs the following:
A MyProperty
C MyProperty
E MyProperty
Note that this code depends on using the MethodInfo of the get method associated with the property. If you happen to have set-only properties, then you'll need to do some extra checks to handle that case.

but not including those that will never have different values?
It seems you are expecting the Reflection system to include rules for this very particular case. If it did, somebody else would complain that the B and D properties were missing.
But I think the answer is: D.MyProperty is listed from a recursive call. You know you already listed E.MyProperty so it might seem unnecessary but what if you called GetProperties(D)? Would you like it to be omitted?

Each of these is both a declaration and implementation (as none of them are abstract, so they all define method bodies). The keywords override and new are little more than hints to the runtime about which implementation to pick given the context of an instance. With reflection, you're bypassing normal inheritance tracing and invoking a specific implementation.
Given that, you can still figure out which of these will be the "root" call made from various points in the hierarchy. Recall that properties in .NET are pretty much syntactic sugar for a specific getter and setter method structure and a backing field, accessed as if the accessors were the field itself. Thus, a PropertyInfo exposes GetGetMethod() and GetSetMethod() which will return MethodInfo objects. You should only need one of the two as they'll both have the inheritance qualifiers given to the property, but make sure that your property has a get or a set at all levels of the hierarchy or this will blow up.
Now, MethodInfo exposes several properties regarding accessibility and inheritance. Of importance to you is the IsHideBySig property. If this returns true, then this method, as declared on the current type, is hiding an identical signature on its parent using the new keyword. So, in your code, you want to look at the members, and test two things; whether the type has a base type other than Object (or an abstract type you specify), and whether IsHideBySig on the getter or setter is true. If either of those is true, this is a "root" implementation for any type between the current type and the next most derived type with a similar "root".
So, your foreach would end up looking something like this:
foreach (var item in type.GetProperties(
BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
.Where(pi=>pi.GetGetMethod().IsHideBySig || pi.ReflectedType.BaseType == typeof(Object))
{
Console.WriteLine("{0} {1}", type.Name, item.Name);
}
Now remember that these "roots" are not the ones that will be called, unless their children explicitly call them using the base identifier, and this can happen regardless of whether the current property hides or overrides its parent. The difference is in which implementation will be invoked by the runtime when an instance is cast as one of its ancestor types. In that case, the implementation chosen is that of the most derived type in the inheritance chain between cast and actual types, starting from the cast type, which does not hide its parent. If the most direct descendant of the cast type hides its parent, the cast type's implementation is used regardless of what that implementation does to its parent.
In your hierarchy, those would be B, D and E. If you declared a new E and invoked MyProperty, you'd get E's implementation. Then, if you passed it to a method that takes any A and accesses MyProperty, it would use B's implementation. If you declared an E and treated it as a C, it would use D's implementation. If you created a C and treated it as such, you'd get C's implementation (because a C is not a D), but if you treated it as an A you'd get B's implementation.

Related

Getter method generated by System.Reflection.Emit fails to return primitive types, but works as expected for non-primitive objects

I'm trying to write a program that creates a dynamic "Wrapper" class around an existing class with properties, and redirects all the virtual properties getters and setters to a dedicated GetValue and SetValue methods in BaseClass. It's a bit difficult to explain, so here's the code so far:
public abstract class BaseClass
{
protected void SetValue(string propertyName, object value) { ... }
protected object? GetValue(string propertyName) { ... }
}
public class DataClass : BaseClass
{
public virtual string? StrValue { get; set; }
public virtual int IntValue { get; set; }
public virtual bool BoolValue { get; set; }
public virtual List<float>? FloatListValue { get; set; }
}
In this example, my code generates a new class called DataClassWrapper that inherits from DataClass, and overrides all the properties' getter and setter methods with IL code that redirects the call to re respective GetValue and SetValue methods in the base class, passing the property's name as the first argument. The actual method that does all this is a bit too long for this post, but it can be viewed here.
Here's the code that generates the setter for each property: (works correctly in all cases)
setMethodGenerator.Emit(OpCodes.Ldarg_0); // 'this'
setMethodGenerator.Emit(OpCodes.Ldstr, propertyInfo.Name); // 1st argument of SetValue
setMethodGenerator.Emit(OpCodes.Ldarg_1); // value passed into this setter, aka. `value`
setMethodGenerator.Emit(OpCodes.Box, propertyInfo.PropertyType); // cast it to `object`
setMethodGenerator.EmitCall(OpCodes.Call, baseSetterMethod, Type.EmptyTypes); // call SetValue
setMethodGenerator.Emit(OpCodes.Ret); // return
where propertyInfo describes a property from DataClass, and baseSetterMethod references the SetValue() method from the base class.
Getter:
getMethodGenerator.Emit(OpCodes.Ldarg_0); // 'this'
getMethodGenerator.Emit(OpCodes.Ldstr, propertyInfo.Name); // 1st (and only) argument of GetValue
getMethodGenerator.EmitCall(OpCodes.Call, baseGetterMethod, Type.EmptyTypes); // call GetValue
getMethodGenerator.Emit(OpCodes.Castclass, propertyInfo.PropertyType); // cast result to expected type
getMethodGenerator.Emit(OpCodes.Ret); // return it
And some example usage:
var type = CreateDynamicType(typeof(DataClass), baseGetterMethod, baseSetterMethod);
var inst = (DataClass) Activator.CreateInstance(type)!;
inst.IntValue = 1123;
Console.Out.WriteLine(inst.IntValue);
I can read and write the properties StrValue and FloatListValue without any issues, my custom GetValue and SetValue methods are being called as they should be.
However if I try to read a primitive property like BoolValue or IntValue, it returns a seemingly random garbage number (for example -1151033224 the last time I ran this code). If I convert my IntValue into a nullable IntValue? value, it still returns gibberish, but this time the random numbers are much smaller (in the 0-700 range).
The setter method does receive the original int value correctly, and the getter also retrieves it intact, so the problem must be around the generated IL code that calls the getter. But it only seems to happen with primitive types. Does anyone have an idea?
I think your problem is the castclass instruction. The documentation says:
typeTok [the argument] is a metadata token (a typeref, typedef or
typespec), indicating the desired class. If typeTok is a non-nullable
value type or a generic parameter type it is interpreted as “boxed”
typeTok. If typeTok is a nullable type, Nullable, it is interpreted
as “boxed” T.
Unlike coercions (§III.1.6) and conversions (§III.3.27), a cast never changes the actual type of an object and preserves object identity (see Partition I)
That means that if the object is a boxed instance of a value type, castclass does not unbox it but retains the object reference. So this will actually return the managed(!) address of the object, which is useless. In case of a value type, you need to use an unbox.any instruction.

Getting Nested Types from Higher in Hierarchy in C#

I have a few classes called SortMethod which inherit from an abstract class called ASortMethod. Each of these classes is nested in another class. Right now, I'm dealing with the SortMethod inside of a class called CitationCollection.
There's another class I'm dealing with called CustomSortDictionary. This has to handle the given SortMethod type, but it's unknown which SortMethod type will be given, so I store a variable Type sortMethod in CustomSortDictionary.
This means I unfortunately have to deal with lots of messy reflection. Within the given Type sortMethod, there are two main things I'm looking to access. The first I was able to access using the below code, but the second I'm having trouble getting to.
BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
// Accessing the first
MethodInfo m = SortMethod.GetMethod("ConstructCustomSortMethods", bindingFlags);
m.Invoke(null, null);
// Accessing the second
IDCollection customSort = (IDCollection)SortMethod.GetNestedType("CustomSort", bindingFlags).GetField("Methods").GetValue(null);
I've tried a few different combinations of BindingFlags to try to get to the nested type in the second piece of code, but I can't access it. I think the issue is that SortMethod.CustomSort.Methods is declared within ASortMethod, which is one step up the hierarchical ladder from CitationCollection.SortMethod.
How would I properly access this second item using reflection?
See this link for the full code.
UPDATE:
I found this from Microsoft's website, which may explain my issue:
BindingFlags.FlattenHierarchy
Specifies that public and protected static members up the hierarchy should be returned. Private static members in inherited classes are not returned. Static members include fields, methods, events, and properties. Nested types are not returned.
Your sort method type looks like this right?
public enum SortType { Ascend, Descend, FlyingTriangle }
You may want to use an interface so that all methods implementing it are required to either accept or reject a requested sort.
Example
public interface ISortable
{
public bool IsValidContext(object record, SortType type);
}
public class SortAlpha : ISortable
{
public bool IsValidContext(object record, SortType type)
{
return type == SortType.Ascend ? true : false; // example
}
}
public class SortBeta : ISortable
{
public bool IsValidContext(object record, SortType type)
{
return type == SortType.Descend && record is HtmlDocument; // example
}
}
You can have a method iterate trough the classes implementing the interface to find and return the right one.
Since the type CustomSort is always nested in ASortMethod you could just get it directly:
((IDCollection)typeof(ASortMethod.CustomSort).GetField("Methods").GetValue(null)).Add(ref name);
When you can not for some reason you could walk up the base types until you reach object to find the enclosing type of CustomSort
((IDCollection)FindBase(SortMethod).GetNestedType("CustomSort", bindingFlags).GetField("Methods").GetValue(null)).Add(ref name);
static Type FindBase(Type t)
{
if (t.BaseType != typeof (object))
return FindBase(t.BaseType);
return t;
}

Check if a "Type" override a dynamic type

We are giving some repetitive jobs to a consultant company, we just have a few constraints that could not be checked by compilation, like a requirement to override a specific property in all class implementing a specific interface.
The property of the interface, which should be overrided in all classes has the following signature:
dynamic Definition{get;}
I found this stackoverflow question: How to find out if property is inherited from a base class or declared in derived?
Which is closed to my case, but in my case, the property is defined is inherited class and overrided in this one:
public class ClassA:IMyInterface
{
public virtual dynamic Definition{get{ /*return SomethingSpecificToClassA;*/}}
}
public class ClassB:ClassA
{
public override dynamic Definition{get{ /*return SomethingSpecificToClassB;*/}}
}
//The end goal is to know if ClassB has correctly overriden the property
bool overriden = typeof(ClassB)GetProperties(...).Any(p=>p.Name=="Definition");
This is the solution: you ask ClassB its interface map, you look for the method you want in the interface map and then you look where the implementation method (classMethod) is declared.
var interfaceMethod = typeof(I).GetProperty("Definition").GetGetMethod();
var map = typeof(ClassB).GetInterfaceMap(typeof(I));
var ix = Array.IndexOf(map.InterfaceMethods, interfaceMethod);
var classMethod = map.TargetMethods[ix];
bool isDeclaredInClass = classMethod.DeclaringType == typeof(ClassB);
You can find for property declared only in your type of interests:
var prop = typeof (ClassB).GetProperty("Definition", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Then you can then check if its getter is virtual:
prop.GetMethod.IsVirtual
which will be false if Definition hides (or uses new) in ClassB

ReflectedType from MemberExpression

Given this code:
static void Main(string[] args)
{
Expression<Func<SomeDerivedClass, object>> test = i => i.Prop;
var body = (UnaryExpression) test.Body;
Console.WriteLine(((MemberExpression) body.Operand).Member.ReflectedType);
}
public class SomeClass
{
public int Prop { get; private set; }
}
public class SomeDerivedClass : SomeClass
{
}
I would have expected ReflectedType to be SomeDerivedClass given that it is the type of the parameter for the expression. But it is SomeClass, which is - if i understand correctly - the declaring type.
Why is that?
The precise details of how expression trees get built are largely unspecified. The only thing that matters is that the expression tree corresponds to the C# syntax used to build the expression tree. In an ordinary C# expression, there is only the equivalent of DeclaringType, which gets encoded in the IL. The member isn't accessed through reflection at all, so there is no ReflectedType to consider. Because there is no ReflectedType to consider, the two different PropertyInfo objects corresponds equally well to the original source code.
For a potential reason why, consider this somewhat evil derived class:
public class SomeClass
{
public int Prop { get; set; }
}
public class SomeDerivedClass : SomeClass
{
public int get_Prop() { return 4; }
}
Here, the base class's Prop getter is not overridden, but the original get_Prop property compiler-generated getter function is only available through the base class. Therefore, the only correct property getter for Prop is SomeClass.get_Prop. SomeDerivedClass.get_Prop must not be used, even if Prop is accessed on an object statically known to be a SomeDerivedClass.
Combine this with the fact that internally, the C# compiler-generated code to build the expression tree obtains the appropriate PropertyInfo objects by getting the property getter methods, and asking the runtime to find the corresponding PropertyInfo, and you have your answer: the property getter method can only reliably be obtained from SomeClass, therefore you will also get the PropertyInfo from SomeClass.
That's because the expression evaluates to Prop which is defined in SomeClass and not in SomeDerivedClass. Notice that SomeDerivedClass is merely the type of your test lambda parameter, so it has nothing to do with the type of its body, which is an UnaryExpression accessing a property located in SomeClass.
Try also adding Prop to SomeDerivedClass, and you'll get your expected result.
The ReflectedType property retrieves the Type object that was used to obtain this instance of MemberInfo. This may differ from the value of the DeclaringType property if this MemberInfo object represents a member that is inherited from a base class.
http://msdn.microsoft.com/en-us/library/system.reflection.memberinfo.reflectedtype.aspx

Identifying properties that override base properties or implement interfaces

I am given:
A class "T" which implements properties that are decorated with Attributes that I am interested in.
A PropertyInfo "p" representing a property belonging to (1) an interface "I" that T implements, (2) a base class "B" that T inherits from, or (3) the class T itself.
I need to get the Attributes defined on (or inherited by) the properties in T, even if p's DeclaringType is an interface that T implements or a class that T inherits from. So I need a way to get from p to the PropertyInfo that actually exists on T. Thus it seems that there are 3 cases:
p.DeclaringType == typeof(T)
This is the trivial case. I can iterate through T's properties until I find the match. Example:
return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(property => property == p)
p.DeclaringType == typeof(I) where I is an interface that T implements
This is more complicated. I found that I can use an InterfaceMapping to find the corresponding implementation of the p in T. It seems kind of hackish, but here what works:
if (p.DeclaringType.IsInterface &&
typeof(T).GetInterfaces().Contains(p.DeclaringType))
{
InterfaceMapping map = typeof(T).GetInterfaceMap(p.DeclaringType);
MethodInfo getMethod = p.GetGetMethod();
for (int i = 0; i < map.InterfaceMethods.Length; i++)
{
if (map.InterfaceMethods[i] == getMethod)
{
MethodInfo target = map.TargetMethods[i];
return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(property => property.GetGetMethod() == target);
}
}
}
p.DeclaringType == typeof(B) where B is a class that T inherits from
I have not yet been able to figure out how to identify the property on T that overrides a virtual property p defined in Ts base class B.
So my questions are
In case 3 how do I find the PropertyInfo on T that overrides the property p on B?
Is there a better way to do all three? Perhaps a way to unify the three cases.
I think you're missing a case : it is possible that T just inherits the property from B, without overriding it (unless you know for sure this won't happen in your specific scenario).
Anyway, you just need to search the property by name, using typeof(T).GetProperty, since there can't be 2 properties with the same name in a given class (unlike methods, which can have several overloads). However, you need to watch out for the case where T hides the property inherited from B, using the new modifier. To handle that case, you can check the Attributes of the property's getter method (obtained with GetGetMethod) : if the NewSlot flag is present, it hides the inherited getter.
I found a way to answer case 3. The key is MethodInfo.GetBaseDefinition
if (typeof(T).IsSubclassOf(p.DeclaringType))
{
MethodInfo baseDefinition = p.GetGetMethod().GetBaseDefinition();
return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(property => property.GetGetMethod().GetBaseDefinition() == baseDefinition);
}
However this only works for properties that have been overridden on T.
Edit:
By comparing the following, it doesn't matter if the properties have or haven't been overriden on T:
property.GetGetMethod().GetBaseDefinition().MetadataToken == baseDefinition.MetadataToken

Categories