我想创建一些现有的代码模块(IMyDesiredType
)来加载MEF。模块主要有一些构造函数参数,我想用MEF(ImportingConstructor
)提供。到目前为止,这个工作正常。
现在出现问题是因为有时主机应用程序中的依赖项不可用(它们为空)。模块将按惯例抛出ArgumentNullException
,我不想改变它。但是我希望MEF忽略这些对象(不包括在对象图中)。
[Export(typeof(IMyDesiredType))]
class MyModule : IMyDesiredType{
[ImportingConstructor]
public MyModule(object aNecessaryDependency){
if(aNecessaryDependency==null) throw new ArgumentNullException(nameof(aNecessaryDependency))
}
}
为了获得这个,我让MEF创建Lazy<IMyDesiredType>
个实例并逐个初始化它们。
foreach(var myLazy in collectionOfMefExports){
try{
myLazy.Value // do something with the value, so the object gets composed
}catch(CompositionException){
// Here I get the ArgumentNullException wrapped in a CompositionException
// and also can work around it. However because of the exception handling
// is on the first hand in MEF, VS will break always in the throwing
// constructor of the module
continue; // Go to the next module after logging etc.
}
}
这里的问题是,我必须从模块的构造函数中捕获CompositionException
而不是直接Exception
(主要是ArgumentNullException
)。因此,Visual-Studio会在每个模块上中断,因为Exception不会从用户代码中获取。对此明显的解决方案是告诉视觉工作室不要打破ArgumentNullException
类型,但这对我来说非常“苛刻”。在任何其他地方,我希望VS打破ArgumentNullException
s。
是否有另一种模式,我可以使MEF不向图形中添加组件,其中声明了依赖项([Export]
),但它的值为null,或者是否存在MEF类的方法我可以在派生类中重写并在前端捕获构造函数异常吗?
请发表评论,如果问题不明确,我不是母语为英语的人,因此可能会将问题语言化为混乱。
答案 0 :(得分:1)
不幸的是,对你所要求的支持在某种程度上是有限的。
Visual Studio允许按异常类型配置调试器是否应该中断。当您尝试根据执行上下文显示/隐藏相同类型的异常时,这并没有什么帮助。您仍然可以派生自己的异常类型并在导入构造函数中使用它。这将允许您按异常类型配置中断,但不会在MEF组合和其他代码之间产生差异。
此外,调试器可以将方法标记为忽略方法。请参阅此相关答案Don't stop debugger at THAT exception when it's thrown and caught。
忽略[DebuggerStepThrough]
,因为据报道它不可靠,选项一是[DebuggerHidden]
。我想添加另一位候选人:[DebuggerNonUserCode]
。这与VS选项一起播放&#34;只启用我的代码&#34; (见http://blog.functionalfun.net/2008/05/debuggernonusercode-suppressing.html)。
因此虽然[DebuggerHidden]
永远不会因为抛出它的构造函数中的异常而中断,而是会在下一个周围的用户代码中报告它,[DebuggerNonUserCode]
允许您根据构造函数忽略或中断在您的VS调试设置上。只要&#34;只启用我的代码&#34;设置后,两个属性的行为应该相同。
假设MEF初始化在调试器隐藏代码中完全处理,对于非MEF构造函数调用,调试器在第一次到达未标记为隐藏的周围函数时将中断。
答案 1 :(得分:0)
听起来只有你知道哪些组件很重要而哪些组件不重要。 你可能想做一些事情,比如像你现在一样在try catch中包装组件初始化,并通过配置查找来决定代码中是否存在这个特殊异常。
基本上你需要自己构建规则,但无论哪种方式失败的组件加载都是失败的,所以抛出异常的组件无法正常添加到图中。
普遍接受的方法似乎是删除故障组件然后重新构图...
How do I get MEF to recompose when I change a part?
...
这可能会帮助您诊断下一步该做什么/做什么。
https://blogs.msdn.microsoft.com/dsplaisted/2010/07/13/how-to-debug-and-diagnose-mef-failures/
答案 2 :(得分:0)
我可能正朝着错误的方向前进,但是对于未处理的案例,默认实施的抽象工厂是否有帮助?
我用这个来依靠统一DI ...毫无疑问有趣的问题!
<Export(GetType(IComponent))>
Public Class DependencyResolver
Implements IComponent
Public Sub SetUp(registerComponent As IRegisterComponent) Implements IComponent.SetUp
'General
registerComponent.RegisterType(Of IDataContextAsync, dbEcommEntities)()
'DomainLogic
registerComponent.RegisterType(Of IUserDomainLogic, MfrUserDomainLogic)()
'Services
registerComponent.RegisterType(Of ICompanyService, CompanyService)()
End Sub
End Class
注入构造函数 - 我将MEF导出到另一个具有自己的依赖项解析器的类库中。在每个Web应用程序中,我然后注册新应用程序的组件。然后,我可以通过注入我的mvc控制器的构造函数来扩展从MEF导出依赖项解析器接收的每个部分。 在组件加载器中,然后使用dll加载容器,并且还可以通过在事实之后添加unity.config来扩展依赖项。
Private Shared Sub RegisterDependencies(container As IUnityContainer)
'load services
ComponentLoader.LoadContainer(container, ".\\bin", "Service.dll")
'load config
'container.LoadConfiguration()
End Sub
答案 3 :(得分:0)
解决问题的唯一方法是在访问值之前检查Value是否实际创建。
if(myLazy.IsValueCreated)
myLazy.Value // do something with the value, so the object gets composed
您可以阅读更多相关信息here。
注意:如果你有可选的依赖项,系统可以在没有它们的情况下工作,那么不要在构造函数中放置Argument null check。它将使它们在合成期间成为必需的依赖项。
正如您已经提到的,当参数为null时,您不希望更改抛出异常的约定。好吧,如果你知道系统可以在没有这些依赖关系的情况下工作,那么你可以避免对这种依赖关系进行检查。