在不使用静态 class 的情况下调用 class 的扩展方法,而是通过使用 class iteslf 使用反射

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

我想调用 Method2,它是使用 MyClass 类型的 MyClass 的扩展方法。我想知道这是否可能。

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();

        }

    }
}

当然有可能,唯一需要注意的是 .Net Reflection 不理解 Extension Method 语法糖 this.

请记住,扩展方法是一种 C# 结构,在给定第一个参数(标有 this关键字)

简而言之,您必须以静态 class 为目标并将 MyClass 实例作为第一个参数

var myClass = new MyClass();

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

whereMethods.Invoke(null, new object[]{ myClass } );

输出

You have called ex Method 2

Full Demo Here

更新

I dont want to use typeof(MyClassStatic).. I want to use typeof(MyClass)

Method2 不是 MyClass 的成员,您不能以我能想到的任何方式强制它成为成员。

这个其实是有办法的,就是有点难。如果您没有忘记将 this 关键字放置到您的扩展方法参数中,C#​​ 编译器将向此方法和此 class 发送 ExtensionAttribute。知道这一点,你就可以找到这个扩展方法并执行它:

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 });
        }
    }
}

如果您不确定在哪个程序集中搜索扩展方法,您可以尝试搜索全部:

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

请注意:反射。真的很慢。即使您使用 .Where(type => type.IsSealed) 或任何其他过滤器过滤所有类型,它仍然 非常慢 。如果您有任何其他方式来调用扩展方法中的代码,您可能应该使用这种方式。