You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MEF中仅获取到Worker方法,如何获取所有标记MethodGetterAttribute的方法?

问题原因分析

你当前的代码只能拿到Worker的方法,核心问题出在MEF的导出合同匹配上:container.GetExports<Action<Worker>>()只会精准匹配签名为Action<Worker>的导出方法。另外两个GetName方法的参数分别是Model.First.Person和Model.First.Second.Person(即使类名相同,不同命名空间下也是完全不同的类型),对应的委托类型是Action<Model.First.Person>和Action<Model.First.Second.Person>,和Action<Worker>不属于同一合同,所以MEF不会返回它们。

解决方案

要获取所有标记MethodGetterAttribute的方法,我们需要跳出“指定具体委托类型”的限制,改用统一的导出标识或者通用类型来获取所有相关导出,再通过反射处理执行逻辑。

方案1:为特性指定统一的导出合同名称

首先修改你的MethodGetterAttribute,在继承ExportAttribute时指定一个统一的合同名称,这样所有标记该特性的方法都会导出到同一个合同下:

[AttributeUsage(AttributeTargets.Method)]
public class MethodGetterAttribute : ExportAttribute
{
    // 指定统一的合同名称,比如"IMethodGetter"
    public MethodGetterAttribute() : base("IMethodGetter")
    {
    }
}

然后在获取导出时,直接通过这个合同名称获取所有相关导出:

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

// 通过统一合同名称获取所有标记MethodGetter的方法
var allMethodExports = container.GetExports<object>("IMethodGetter");

// 准备好各个方法需要的参数实例(根据你的实际业务创建)
var firstPerson = new Model.First.Person();
var secondPerson = new Model.First.Second.Person();
var worker = new Model.First.Second.Third.Worker();

// 遍历所有导出,根据参数类型执行方法
foreach (var export in allMethodExports)
{
    var action = export.Value;
    var actionType = action.GetType();
    
    // 获取委托的泛型参数类型(即方法的参数类型)
    var parameterType = actionType.GetGenericArguments()[0];
    
    // 根据参数类型匹配对应的实例并执行
    if (parameterType == typeof(Model.First.Person))
    {
        ((Action<Model.First.Person>)action).Invoke(firstPerson);
    }
    else if (parameterType == typeof(Model.First.Second.Person))
    {
        ((Action<Model.First.Second.Person>)action).Invoke(secondPerson);
    }
    else if (parameterType == typeof(Model.First.Second.Third.Worker))
    {
        ((Action<Model.First.Second.Third.Worker>)action).Invoke(worker);
    }
}

方案2:不修改特性,直接筛选所有导出

如果你不想修改MethodGetterAttribute,可以直接获取所有导出,然后筛选出标记了该特性的方法:

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

// 获取所有导出,筛选出标记了MethodGetterAttribute的委托方法
var allMethodExports = container.GetExports<object>()
    .Where(export => 
        export.Value is Delegate &&
        export.Value.GetType().GetCustomAttributes<MethodGetterAttribute>().Any())
    .ToList();

// 准备参数实例
var firstPerson = new Model.First.Person();
var secondPerson = new Model.First.Second.Person();
var worker = new Model.First.Second.Third.Worker();

// 遍历执行方法,用DynamicInvoke简化类型转换
foreach (var export in allMethodExports)
{
    var action = (Delegate)export.Value;
    var parameterType = action.GetType().GetGenericArguments()[0];
    
    if (parameterType == typeof(Model.First.Person))
    {
        action.DynamicInvoke(firstPerson);
    }
    else if (parameterType == typeof(Model.First.Second.Person))
    {
        action.DynamicInvoke(secondPerson);
    }
    else if (parameterType == typeof(Model.First.Second.Third.Worker))
    {
        action.DynamicInvoke(worker);
    }
}
额外注意点

如果Model.First.Person和Model.First.Second.Person其实是同一个类(只是在不同命名空间下引用),那它们的完全限定名一致,Action<Person>的类型也会相同,此时你可以直接用GetExports<Action<Person>>()获取前两个方法,再单独获取Action<Worker>的方法,但从你的代码结构看,它们应该是不同的类,所以通用方案更稳妥。

内容的提问来源于stack exchange,提问作者Dilshod K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:25:20