Как получить все методы в MEF - PullRequest
2 голосов
/ 19 апреля 2019

У меня есть класс атрибута

[AttributeUsage(AttributeTargets.Method)]
public class MethodGetterAttribute : ExportAttribute
{

}

Я использую его в методе нескольких пространств имен:

namespace Model.First
{
    public class PersonBL
    {
        [MethodGetter]
        public void GetName(Person person)
        {

        }
    }
}

namespace Model.First.Second
{
    public class PersonBL
    {
        [MethodGetter]
        public void GetName(Person person)
        {

        }
    }
}

namespace Model.First.Second.Third
{
    public class WorkerBL
    {
        [MethodGetter]
        public void GetName(Worker worker)
        {

        }
    }
}

Я хочу упорядочить все методы и запустить их один за другим.Чтобы получить методы, я делаю это:

Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(assemblies.FirstOrDefault(a => a.GetName().Name.Contains("Model"))));
var container = new CompositionContainer(catalog);
var importedMethods = container.GetExports<Action<Worker>>() as IEnumerable<Lazy<Action<Worker>>>;
var result = importedMethods.Select(a => a.Value.Target).ToList();// Here i'm getting only worker's method

Но он возвращает только метод Worker's.Как я могу получить все три метода от работника?

1 Ответ

1 голос
/ 20 апреля 2019

Ну ... Давайте создадим 4 библиотеки классов

Zero.dll со всеми классами, используемыми в других сборках

using System;
using System.ComponentModel.Composition;
using System.Diagnostics;

namespace Zero
{
    [AttributeUsage(AttributeTargets.Method)]
    public class MethodGetterAttribute : ExportAttribute { }

    public class Person { }

    public class Worker : Person { }

    public static class MethodHelper
    {
        public static string GetMethod()
        {
            var method = new StackTrace().GetFrame(1).GetMethod();
            return $"{method.DeclaringType.FullName} {method}";
        }
    }

    public static class Discovery
    {
        public static TDelegate[] GetDelegates<TAttribure, TDelegate>()
            where TAttribure : Attribute
            where TDelegate : Delegate
        {
            return Directory.GetFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "*.dll")
                            .Select(file => { try { return Assembly.LoadFrom(file); } catch { return null; } })
                            .OfType<Assembly>()
                            .Append(Assembly.GetEntryAssembly())
                            .SelectMany(assembly => assembly.GetTypes())
                            .SelectMany(type => type.GetMethods())
                            .Where(method => method.GetCustomAttributes(typeof(TAttribure)).Any())
                            .Select(method => Delegate.CreateDelegate(typeof(TDelegate), null, method, false))
                            .OfType<TDelegate>()
                            .ToArray();
        }
    }
}

Model.First.dll ссылается на Zero.dll

using System;
using Zero;

namespace Model.First
{
    public class PersonBL
    {
        [MethodGetter]
        public void GetName(Person person)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }
    }
}

Model.First.Second.dll, ссылающийся на Zero.dll

using System;
using Zero;

namespace Model.First.Second
{
    public class PersonBL
    {
        [MethodGetter]
        public void GetName(Person person)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }

        [MethodGetter]
        public void Incompatible(string s)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }
    }
}

Model.First.Second.Third.dll, ссылающийся на Zero.dll

using System;
using Zero;

namespace Model.First.Second.Third
{
    public class WorkerBL
    {
        [MethodGetter]
        public void GetName(Worker worker)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }

        public void NoAttribute(Worker worker)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }
    }
}

Тогда давайте создадим консольное приложение ConsoleApp.exe, ссылающееся на Zero.dll, Model.First.dll, Model.First.Second.dll и Model.First.Second.Third.dll

using System;
using Zero;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var worker = new Worker();
            foreach (var d in Discovery.GetDelegates<MethodGetterAttribute, Action<Worker>>())
                d.Invoke(worker);
        }        
    }

    public class WorkerBL
    {
        [MethodGetter]
        public void GetName(Worker worker)
        {
            Console.WriteLine(MethodHelper.GetMethod());
        }
    }
}

Давайте создадим Junk.txt, добавим в него какую-нибудь ерунду, такую ​​как bd%E56#EVwD, переименуем файл в Junk.dll, добавим его в каталог файлов .exe и затем запустим приложение.

Вывод:

Model.First.PersonBL Void GetName(Zero.Person)
Model.First.Second.PersonBL Void GetName(Zero.Person)
Model.First.Second.Third.WorkerBL Void GetName(Zero.Worker)
ConsoleApp.WorkerBL Void GetName(Zero.Worker)

Как и ожидалось. Он находит все совместимые методы с указанным атрибутом и возвращает делегаты для них.

...