вызывать метод расширения класса, не используя статический класс, а используя класс iteslf, используя отражение - PullRequest
0 голосов
/ 24 декабря 2018

Я хочу вызвать 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();

        }

    }
}

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

На самом деле, есть способ для этого, но это немного сложно.Если вы не забыли поместить ключевое слово this в свой параметр метода расширения, компилятор C # отправит 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 });
        }
    }
}

Если вы не уверены, в какой сборке искать метод расширения, вы можете попробовать поискать all :

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

Обратите внимание: отражение медленно .Действительно медленно.Даже если вы фильтруете все свои типы с помощью .Where(type => type.IsSealed) или любого другого фильтра, он все равно очень медленный .Если у вас есть какой-либо другой способ вызвать код в вашем методе расширения, вам, вероятно, следует использовать этот способ.

0 голосов
/ 24 декабря 2018

Конечно, возможно, единственное предупреждение: .Net Reflection не понимает Метод расширения Синтаксический сахар this.

Помня, что метод расширения является конструкцией C #, чтобы сэкономить вам пару печатных символов при вызове статического метода статического класса при задании первого параметра (помеченного ключевым словом this)

Короче говоря, вам нужно нацелить статический класс и передать в качестве экземпляра 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

Полная демонстрация здесь

Обновление

Я не хочуиспользовать typeof (MyClassStatic) .. Я хочу использовать typeof (MyClass)

Method2 не является членом MyClass, и вы не можете заставить его быть таковым любым способом, который ямогу думать о.

...