Same for methods too:
I am given two instances of PropertyInfo or methods which have been extracted from the class they sit on via GetProperty()
or GetMember()
etc, (or from a MemberExpression maybe).
I want to determine if they are in fact referring to the same Property or the same Method so
(propertyOne == propertyTwo)
or
(methodOne == methodTwo)
Clearly that isn't going to actually work, you might be looking at the same property, but it might have been extracted from different levels of the class hierarchy (in which case generally, propertyOne != propertyTwo
)
Of course, I could look at DeclaringType, and re-request the property, but this starts getting a bit confusing when you start thinking about
At the end of the day, I just want to be able to do an intelligent equality check between two properties or two methods, I'm 80% sure that the above bullet points don't cover all of the edge cases, and while I could just sit down, write a bunch of tests and start playing about, I'm well aware that my low level knowledge of how these concepts are actually implemented is not excellent, and I'm hoping this is an already answered topic and I just suck at searching.
The best answer would give me a couple of methods that achieve the above, explaining what edge cases have been taken care of and why :-)
Clarification:
Literally, I want to make sure they are the same property, here are some examples
public interface IFoo
{
string Bar { get; set; }
}
public class Foo : IFoo
{
string Bar { get; set; }
}
typeof(IFoo).GetProperty("Bar")
and
typeof(Foo).GetProperty("Bar")
Will return two property infos, which are not equal:
public class BaseClass
{
public string SomeProperty { get; set ; }
}
public class DerivedClass : BaseClass { }
typeof(BaseClass).GetMethod("SomeProperty")
and
typeof(DerivedClass).GetProperty("SomeProperty")
I can't actually remember if these two return equal objects now, but in my world they are equal.
Similarly:
public class BaseClass
{
public virtual SomeMethod() { }
}
public class DerivedClass
{
public override SomeMethod() { }
}
typeof(BaseClass).GetMethod("SomeMethod")
and
typeof(DerivedClass).GetProperty("SomeMethod")
Again, these won't match - but I want them to (I know they're not specifically equal, but in my domain they are because they refer to the same original property)
I could do it structurally, but that would be 'wrong'.
Further Notes:
How do you even request the property that's hiding another property? Seems one of my earlier suppositions was invalid, that the default implementation of GetProperty("name")
would refer to the current level by default.
BindingFlags.DeclaringType
appears just to end up returning null!
Taking a look at the PropertyInfo
objects from your IFoo
/Foo
example, we can reach these conclusions:
Type.GetInterfaces
and work from there. Don't forget that interfaces can implement other interfaces, so this has to be recursive.So let's have a crack at it. First, to cover inherited properties:
PropertyInfo GetRootProperty(PropertyInfo pi)
{
var type = pi.DeclaringType;
while (true) {
type = type.BaseType;
if (type == null) {
return pi;
}
var flags = BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.Static;
var inheritedProperty = type.GetProperty(pi.Name, flags);
if (inheritedProperty == null) {
return pi;
}
pi = inheritedProperty;
}
}
Now, to cover properties declared in interfaces (search with DFS):
PropertyInfo GetImplementedProperty(PropertyInfo pi)
{
var type = pi.DeclaringType;
var interfaces = type.GetInterfaces();
if (interfaces.Length == 0) {
return pi;
}
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
var query = from iface in interfaces
let implementedProperty = iface.GetProperty(pi.Name, flags)
where implementedProperty != pi
select implementedProperty;
return query.DefaultIfEmpty(pi).First();
}
Tying these together:
PropertyInfo GetSourceProperty(PropertyInfo pi)
{
var inherited = this.GetRootProperty(pi);
if (inherited != pi) {
return inherited;
}
var implemented = this.GetImplementedProperty(pi);
if (implemented != pi) {
return implemented;
}
return pi;
}
This should work. It doesn't take into account indexed properties with the same name but different types and/or numbers of indexing parameters, so that's left as the proverbial excercise for the reader.
Disclaimer: I didn't even compile this (no time to run tests right now). It is intended as a starting point for "the" answer, since there is none so far.
I'm not exactly sure what you need this for but I guess that your definition of equality in this case is "do the two method infos invoke the same method if invoked"? If so then you really need to specify a type in the comparison too, for example consider this:
public interface IFoo
{
void AMethod();
}
public interface IBar
{
void AMethod();
}
public class FooBar : IFoo, IBar
{
void AMethod();
}
Clearly typeof(IFoo).GetMethod("AMethod") and typeof(IBar).GetMethod("AMethod") are not equal, they are not even related, BUT they do invoke the same method on an instance of FooBar. So what you might like is a comparison method that takes three arguments:
bool WillInvokeSameMethodOnType(MethodInfo method1, MethodInfo method2, Type type)
Check out the class MethodInfoManager in FakeItEasy, it might be what you want: http://code.google.com/p/fakeiteasy/source/browse/Source/FakeItEasy/Core/MethodInfoManager.cs?r=8888fefbc508fb02d5435a3e33774500bec498b3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With