C# mef枚举导出和体系结构
我想让我的插件子系统使用mef,但我没有什么问题,因为我是csharp和mef的新手( 我想做的是:C# mef枚举导出和体系结构,c#,architecture,mef,C#,Architecture,Mef,我想让我的插件子系统使用mef,但我没有什么问题,因为我是csharp和mef的新手( 我想做的是: 每个插件都可以创建自己的接口IPlugin1、IPlugin2 这些接口中的每一个都必须具有指定的加载、卸载功能 使用mef我想枚举所有导出并调用Load/Unload 问题是: a、 我的解决方案好吗?如果没有,我如何改进它(通过使用其他方法) b、 如何使用mef枚举所有导出并调用指定的接口函数 非常感谢所有链接和评论。谢谢大家。如果您希望所有插件接口都遵循自己的接口,那么您应该为他们提供一
非常感谢所有链接和评论。谢谢大家。如果您希望所有插件接口都遵循自己的接口,那么您应该为他们提供一个接口来扩展:
public interface IMyInterface
{
void Load();
void Unload();
}
然后,当这些插件创建自己的接口时,它们应该从您公开提供的接口扩展:
public interface IPlugin1 : IMyInterface
{
void DoPlugin1Func();
}
现在,为了获得在MEF中导出的接口集合,您必须将您的接口标记为InheritedExport:
[InheritedExport(typeof(IMyInterface))]
public interface IMyInterface { ... }
这表明,任何以某种方式从IMyInterface扩展的类都将作为IMyInterface的一种类型导出,甚至在树的下面:
//This class will be exported as an IMyInterface
public class PluginImplementation1 : IPlugin1 { ... }
最后,在代码中的某个地方(如果适用),可以导入IMyInterface实例的集合
public class SomeClass
{
[ImportMany(typeof(IMyInterface))]
private IEnumerable<IMyInterface> Plugins { get; set; }
}
公共类SomeClass
{
[进口数量(类型(IMyInterface))]
私有IEnumerable插件{get;set;}
}
如果一切都连接正确,Plugins
将是类的枚举,通过继承,这些类将导出为IMyInterface
s
资源:
public interface IPlugin : IDisposable
{
void Initialise();
}
通过实施Dispose
方法,您可以通过CompositionContainer
的生存期管理功能自动控制零件。您所有的卸载代码都可以放在那里,下面是一个示例插件:
public interface ILogger : IPlugin
{
void Log(string message);
}
[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
void IPlugin.Initialise()
{
Console.WriteLine("Initialising plugin...");
}
public void Log(string message)
{
Console.WriteLine(message);
}
public virtual void Dispose(bool disposing)
{
if (disposing)
{
Console.WriteLine("Disposing plugin...");
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Dispose
模式允许标准化的机制来清理代码。您的CompositionContainer
实例将跟踪此项,并在清理时将其清理
现在,我想描述的是在InterceptingCatalog中添加的一个很好的功能。这个目录允许您注册拦截策略,它可以让您在导出值返回到调用代码之前访问导出值。其中一个用途是自动确保在bas上调用Initialise
第一次导出实例时的eIPlugin
接口:
public class InitialisePluginStrategy : IExportedValueInterceptor
{
public object Intercept(object value)
{
var plugin = value as IPlugin;
if (plugin != null)
plugin.Initialise();
return value;
}
}
让我们把这些联系起来:
static void Main(string[] args)
{
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var configuration = new InterceptionConfiguration()
.AddInterceptor(new InitialisePluginStrategy());
var interceptingCatalog = new InterceptingCatalog(catalog, configuration);
var container = new CompositionContainer(interceptingCatalog);
var logger = container.GetExportedValue<ILogger>();
logger.Log("test");
Console.ReadKey();
}
static void Main(字符串[]args)
{
var catalog=新的AssemblyCatalog(typeof(Program).Assembly);
var配置=新的侦听配置()
.AddInterceptor(新的初始值为pluginstrategy());
var interceptingCatalog=新的interceptingCatalog(目录,配置);
var container=新合成容器(拦截目录);
var logger=container.GetExportedValue();
logger.Log(“测试”);
Console.ReadKey();
}
如果您运行它,您会注意到我们的ConsoleLogger
会在我们第一次从容器中获取它时自动初始化。我们不必担心它会再次初始化,它只会在创建导出实例时进行初始化,这意味着它遵守单例和非单例场景
此时,您可能会认为这可能有些过分,但实际上这是一个非常优雅的解决方案,可以让您的部件自动启动,并在不再需要时进行处理
当然,如果你想细细控制你的部分是如何被初始化的,你可以在你自己编写的方法中管理这些,你只需要考虑插件状态就可以了。
您可以在
中阅读关于拦截目录的更多信息,您也应该考虑导出<代码> IMyPosie >与<代码> IpLuxIn的导出不相同。我建议,导出为您想要的<代码> iPuxLin 1/代码>,然后执行一个强制转换到<代码> IyMyFutue<代码>,操作<代码>加载<代码> >代码>。卸载。您需要这样做,因为MEF将尝试根据其导出定义实例化类型,这意味着如果您导入IMyInterface
和IPlugin1
,它将实例化至少两个插件的独立实例(无论CreationPolicy
)@Matthew:这绝对是一种可能性。我给出这个例子的原因是OP说他想要一个枚举。在“插件”之间没有公共接口他正在寻找我提出的建议之外的内容,即让它们各自继承自IMyInterface
。另一种方法是将IPlugin1、IPlugin2等作为单个成员导入,然后使用ipartimportssatifiedNotification
接口将它们全部添加到作为IMyInterface
转换的集合中我认为重要的IMyInterface是更好的途径。不过,你应该提出你的替代解决方案。非常感谢。我能说什么?我希望有像你这样的经验。再次感谢你,我不使用asp.net mvc。在桌面应用程序中一切都很好,但在asp.net mvc中,我出现错误“无法转换类型的基本导出值”调用container.GetExportedValue();。是否有mvc应用程序的解决方案或修复此错误?谢谢