Finding the hosting PropertyInfo from the MethodIn

2019-01-14 15:16发布

问题:

I do some type analysis in runtime using Reflection. If I have a MethodInfo instance, how can I figure out if this is a "real" method or is a getter/setter method of a property? And if it is a property, how can I find the its hosting PropertyInfo back?

回答1:

Ecma 335 specifies (but does not demand) that compilers use the get_/set_ prefixes (chapter 22.28). I don't know any language that breaks that recommendation. Making it easy:

public static PropertyInfo GetPropFromMethod(Type t, MethodInfo method) {
  if (!method.IsSpecialName) return null;
  return t.GetProperty(method.Name.Substring(4), 
    BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
}


回答2:

Well, the method behind a getter and setter are "real" methods.

Re tracking back to a property - the pattern (return vs take 1 arg) will help narrow it - but you'll have to call GetGetMethod/GetSetMethod on each to find the property.

You could probably try the Name (less get__/set__) - but that feels brittle. Here's the longer version (no use of Name):

static PropertyInfo GetProperty(MethodInfo method)
{
    bool takesArg = method.GetParameters().Length == 1;
    bool hasReturn = method.ReturnType != typeof(void);
    if (takesArg == hasReturn) return null;
    if (takesArg)
    {
        return method.DeclaringType.GetProperties()
            .Where(prop => prop.GetSetMethod() == method).FirstOrDefault();
    }
    else
    {
        return method.DeclaringType.GetProperties()
            .Where(prop => prop.GetGetMethod() == method).FirstOrDefault();
    }
}


回答3:

Look into MethodBase.IsSpecialName. Methods which shouldn't be plainly visible, such as property accessors, event subscription methods and operator overloads use this flag.

To my knowledge, there isn't a way to find the PropertyInfo without iterating through the properties and comparing the methods.



回答4:

I'd really like to leave this as a comment, but I cant since my rep isnt high enough :(

Theres a bug in Marc Gravell's code: if its an indexer it will return null, even when a parent property exists. Its nice to have that quick-fail, but I think we can only do so when it has neither a return value or a parameter:

    [Pure]
    public static PropertyInfo GetParentProperty(this MethodInfo method)
    {
        if (method == null) throw new ArgumentNullException("method");
        var takesArg = method.GetParameters().Length == 1;
        var hasReturn = method.ReturnType != typeof(void);
        if (!(takesArg || hasReturn)) return null;

        if (takesArg && !hasReturn)
        {
            return method.DeclaringType.GetProperties().FirstOrDefault(prop => prop.GetSetMethod() == method);
        }
        else
        {
            return method.DeclaringType.GetProperties().FirstOrDefault(prop => prop.GetGetMethod() == method);
        }
    }


回答5:

The trick to play with is BindingFlags.DeclaredOnly and IsSpecialName