понедельник, 15 марта 2010 г.

Список методов и Extension методов

Список методов и Extension методов

Однажды обсуждая возможности рефлексии в C# обнаружил некоторую проблему, с получением списка методов, которыми располагает класс. На первый взгляд все очень просто. В пространстве имен System.Reflection есть функционал, доступный разработчику, для получения списка методов класса или списка членов, их применение проиллюстрировано ниже:


public void ListMethodsAndMembers()
{
    Type t = this.GetType();    MethodInfo[] mi = t.GetMethods();    foreach (MethodInfo m in mi)        Console.WriteLine("Method: {0}", m.Name);    MemberInfo[] members = t.GetMembers();    foreach (MemberInfo m in members)        Console.WriteLine("Member: {0}", m.Name);
}


Всё работает, безупречно, и даже довольно быстро, не смотря на то, что это рефлекися...

Всё бы хорошо, но что делать, если в экземпляре класса можно вызвать экстеншн метод, если он доступен в автоподсказке студии, а вот в данном списке он отсутствует?



(Все три метода ExMethodX - Extension, как видите доступны в студийной автоподсказке)


Вся проблема в том, что мы не видим методов расширения в списке GetMethods() .



После нескольких минут сёрфа по инету и чтения MSDN я нашел решение данной проблемы, и, не смотря на то, что такой вариант тяжеловатый, иногда можно обратиться и к нему.

Решение "В ЛОБ", но лучшего пока не нашел, как найду, снова выложу в блог. Смысл решения в следующем методе:

private static IEnumerable<MethodInfo> GetExtensionMethods(Type extendedType)
{
    Assembly assembly = extendedType.Assembly;
    var query = from type in assembly.GetTypes()
                where type.IsSealed && !type.IsGenericType && !type.IsNested
                from method in type.GetMethods(BindingFlags.Static
                | BindingFlags.Public | BindingFlags.NonPublic)
                where method.IsDefined(typeof(ExtensionAttribute), false)
                where method.GetParameters()[0].ParameterType == extendedType
                select method;
    return query;
}


Итак, вот иллюстрация:

class Program
{
    static void Main(string[] args)    {        var holder = new Holder();        holder.ListMethods();        holder.ListExtensionMethods();        Console.ReadKey();    }
}
    
Реализация класса Holder

namespace Extensions_via_reflection
{
    public class Holder
    {
        public Holder()
        {
            Console.WriteLine("Insatce of Holder created");
        }
        public int InnerMethod()
        {
            Console.WriteLine("public InnerMethod called");
            return 0;
        }
        public void innerMethod()
        {
            Console.WriteLine("private innerMethod called");
        }

        public void ListMethods()
        {
            Type t = this.GetType();
            MethodInfo[] mi = t.GetMethods();
            foreach (MethodInfo m in mi)
                Console.WriteLine("Method: {0}", m.Name);
        }

        public void ListExtensionMethods()
        {
            foreach (var m in GetExtensionMethods(GetType()))
                Console.WriteLine("EXTENSION Method: {0}", m.Name);
        }

        private static IEnumerable GetExtensionMethods(Type extendedType)
        {
            Assembly assembly = extendedType.Assembly;
            var query = from type in assembly.GetTypes()
                        where type.IsSealed && !type.IsGenericType && !type.IsNested
                        from method in type.GetMethods(BindingFlags.Static
                        | BindingFlags.Public | BindingFlags.NonPublic)
                        where method.IsDefined(typeof(ExtensionAttribute), false)
                        where method.GetParameters()[0].ParameterType == extendedType
                        select method;
                        return query;
        }
    }
}

И реализация класса с extension методами для Holder

public static class HolderExtensions
{
    public static void ExMethod(this Holder holder)
    {
        Console.WriteLine("Extension method ExMethod called");
    }
    public static void ExMethod1(this Holder holder)
    {
        Console.WriteLine("Extension method ExMethod1 called");
    }
    public static void ExMethod2(this Holder holder)
    {
        Console.WriteLine("Extension method ExMethod2 called");
    }
}

Результат

Комментариев нет:

Отправить комментарий