How to get all methods in MEF

家住魔仙堡 提交于 2019-12-24 04:12:20

问题


I have attribute class

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

}

I'm using it in method of several namespaces:

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)
        {

        }
    }
}

I want to order all methods and run it one by one. To get methods I'm doing this:

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

But it returns only Worker's method. How can I get all three methods from worker?


回答1:


Well... Let's create 4 class libraries

Zero.dll with all classes used in other assemblies

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

Then let's create console application ConsoleApp.exe referencing Zero.dll, Model.First.dll, Model.First.Second.dll and 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());
        }
    }
}

Let's create Junk.txt, put some nonsense like bd%E56#EVwD into it, rename the file to Junk.dll and add it into .exe file directory and then start the application.

Output is:

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)

As expected. It finds all compatible methods with specified attribute and returns delegates for them.



来源:https://stackoverflow.com/questions/55757595/how-to-get-all-methods-in-mef

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!