Search code examples
c#reflectionextension-methods

invoke the extension method of a class without using static class but by using class iteslf using reflection


I want invoke Method2 which is an extension method of a MyClass using MyClass type. I am wondering if this is possible or not.

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

namespace ConsoleApplication9
{
    public static class MyClassStatic
    {
        public static void Method2(this ConsoleApp2.MyClass obj)
        {
            Console.WriteLine("You have called ex Method 2");
        }
    }

    public interface IClass
    {
        void Method1();
    }

    public class MyClass : ConsoleApp2.IClass
    {
        public void Method1()
        {
            Console.WriteLine("You have called Method 1");
        }
    }

    class Program
    {


        public static void CallWhereMethod()
        {


            var whereMethods = typeof(MyClass)
                .GetMethods(BindingFlags.Static | BindingFlags.Public)
                .Where(mi => mi.Name == "Method2");


            Console.WriteLine(whereMethods.Count());
            // returns zero

        }

        static void Main(string[] args)
        {
            CallWhereMethod();
            Console.ReadKey();

        }

    }
}

Solution

  • Actually, there is a way for this, but it's hard a bit. If you don't forget to place a this keyword to your extension method parameter, C# compiler will emmit ExtensionAttribute to this method and this class. Knowing this, you are able to find this extension method and execute it:

    var myClassType = typeof(MyClass);
    var myClass = new MyClass();
    
    var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
    foreach (var type in assemblyTypes.Where(t => t.GetCustomAttribute<ExtensionAttribute>() != null)
    {
        var typeMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var method in typeMethods.Where(m => m.IsDefined(typeof(ExtensionAttribute), inherit: false))
        {
            if (method.GetParameters()[0].ParameterType == myClassType)
            {
                // here you go
                method.Invoke(null, new object[]{ myClass });
            }
        }
    }
    

    If you unsure in which assembly to search for extension method, you may try to search all:

    var allLoadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
    

    Please note: reflection is slow. Really slow. Even you filter all of your types with .Where(type => type.IsSealed) or any other filter, it is still dead slow. If you have any other way to invoke the code in your extension method, you probably should use that way.