4

That is, how can I, given a MethodInfo check if a method is the getter or setter of a property or the adder or remover or firer (?) of an event, without enumerating all the Property/EventInfos in the containing type. Does the compiler mark these methods with some information that would allow me to know when my MethodInfo is one?

AlphaModder
  • 3,266
  • 2
  • 28
  • 44
  • What do you mean a method is an event? Do you mean an "Add" or "Remove" event methods? – Yacoub Massad Dec 29 '15 at 00:04
  • 1
    for properties check this question: http://stackoverflow.com/questions/16718772/is-the-method-naming-for-property-getters-setters-standardized-in-il – Yacoub Massad Dec 29 '15 at 00:06
  • 1
    Only whether it is an event/property, or the property attached to it? Or that property/event. My first guess is that you cannot. Furthermore can you please make your question a bit more *canned*? Now one has to look to the title. – Willem Van Onsem Dec 29 '15 at 00:09
  • @Yacoub Massad Yeah. I believe those are also called accessors. Title is meant to be (event or property) accessor, rather than (event or (property accessor)). – AlphaModder Dec 29 '15 at 03:37
  • @WillemVanOnsem I don't need to know the property, no. I just need to know if the method is one at all. I've edited the question to contain more in the body. – AlphaModder Dec 29 '15 at 03:39
  • 1
    How reliable does this need to be? Unless you go over all properties and events, it is unavoidable that you will get it wrong for some methods of some assemblies. But if for instance such assemblies are never produced by the C# compiler, you might not care. –  Dec 29 '15 at 07:09

3 Answers3

1

This is not a complete solution but on the condition that the property type is not EventHandler, you can tell property get/set methods from event add/remove methods by checking their parameters and return values.

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

class Program
{
    static void Main(string[] args)
    {
        foreach (var methodInfo in typeof(TestClass).GetMethods())
        {
            if (!methodInfo.IsSpecialName)
                continue;

            CheckMethod(methodInfo);
        }

        // Method get_Name -> Property Get
        // Method set_Name -> Property Set
        // Method add_NameChanged -> Event Add/Remove
        // Method remove_NameChanged -> Event Add/Remove
    }

    static void CheckMethod(MethodInfo info)
    {
        var parameter = info.GetParameters().FirstOrDefault();
        if (parameter != null)
        {
            if (parameter.ParameterType.BaseType == typeof(MulticastDelegate))
            {
                Trace.WriteLine($"Method {info.Name} -> Event Add/Remove");
            }
            else
            {
                Trace.WriteLine($"Method {info.Name} -> Property Set");
            }
        }
        else if (info.ReturnType != typeof(void))
        {
            Trace.WriteLine($"Method {info.Name} -> Property Get");
        }
    }
}

public class TestClass
{
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value)
                return;

            _name = value;
            NameChanged?.Invoke(this, value);
        }
    }
    private string _name;

    public event EventHandler<string> NameChanged;
}
emoacht
  • 2,764
  • 1
  • 13
  • 24
1

At least one difference between a manually declared method and one that was generated by the compiler is the presence of a SpecialName attribute in its MethodInfo object:

To find out which property the method is linked to you would inspect PropertyInfo objects to find their corresponding GetMethod and SetMethod properties, which would link to those methods.

Example LINQPad program:

void Main()
{
    typeof(Test).GetProperties().Select(property => new { property.MetadataToken, property.Name, getter = property.GetMethod?.MetadataToken, setter = property.SetMethod?.MetadataToken }).Dump();
    typeof(Test).GetMethods().Select(method => new { method.MetadataToken, method.Name, IsSpecial = (method.Attributes & MethodAttributes.SpecialName) != 0 }).Dump();
}

public class Test
{
    public int Value
    {
        get;
        set;
    }
}

Output:

enter image description here

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
1

MethodInfo.IsSpecialName is set to true for properties and events accessors, also for some other special methods as operators overload and etc. So you can check this flag along with checking the parameter type. The following test program will output the event add/remove accessors:

public class MyEventClass {
private event EventHandler test;
public event EventHandler TestEven {
  add { test += value; }
  remove { test -= value; }
}

}

class Program { static void Main(string[] args) {

  Type myTestClassType = typeof (MyEventClass);
  var methods = myTestClassType.GetMethods();
  foreach (var methodInfo in methods)
  {
    if (methodInfo.IsSpecialName)
    {
      var parameters = methodInfo.GetParameters();
      if (parameters.Count() == 1 && parameters.ElementAt(0).ParameterType == typeof (EventHandler) &&
          (methodInfo.Name.Contains("add") || methodInfo.Name.Contains("remove")))
      {
        Console.WriteLine(methodInfo.Name);
      }

    }
  }

}

}

Radin Gospodinov
  • 2,313
  • 13
  • 14