忽略构造函数异常与MEF没有Visual Studio打破例外

忽略构造函数异常与MEF没有Visual Studio打破例外

问题描述:

我想创建一些现有的代码模块(IMyDesiredType)加载MEF。模块主要有一些我想提供给MEF的构造函数参数(ImportingConstructor)。到目前为止,这工作正常。忽略构造函数异常与MEF没有Visual Studio打破例外

现在出现了这个问题,因为有时候主机应用程序中的依赖关系不可用(它们为空)。这些模块将按照惯例抛出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)。因此,由于Exception不是从用户代码捕获的,所以Visual-Studio在每个模块上都会中断。明显的解决办法是,告诉视觉工作室不要打破ArgumentNullException -types,但这对我来说感觉非常“黑客”。而在其他任何地方,我都希望VS在ArgumentNullException之间突破。

是否有另一种模式,我可以让MEF不向图中添加组件,其中声明了依赖关系([Export]),但它的值为null,或者是否存在我可以覆盖的MEF类的方法在派生类中,并抓住构造函数的例外呢?

请留下评论,如果问题不明确,我不是英语母语的人,因此也许这个问题是言辞混乱的。

+1

您是否已经试过'[DebuggerHidden]'和[DebuggerStepThrough]属性作为答案? http://*.com/questions/1420390/dont-stop-debugger-at-that-exception-when-its-thrown-and-caught#3455100 – grek40

+0

非常感谢您的建议。可悲的是,它的工作方式是:我必须装饰导出模块的每个构造函数,但是它们不会在所有运行时环境中抛出这些异常,而且不仅仅是通过MEF将它们用作简单插件的异常。 – HCL

+0

是防止“Visual-Studio在每个模块上出现故障......”的问题? – Julian

不幸的是,对你所要求的支持有所限制。

Visual Studio允许通过异常类型来配置调试器是否应该中断。当您尝试根据执行上下文显示/隐藏相同类型的异常时,这并没有真正的帮助。仍然可以派生自己的异常类型并在导入构造函数中使用它。这将允许您按异常类型配置中断,但不会影响MEF组合和其他代码之间的差异。

此外,方法可以被标记为被调试器忽略。看到这个相关的答案Don't stop debugger at THAT exception when it's thrown and caught

无视[DebuggerStepThrough],因为据报道是不可靠的,选项一是[DebuggerHidden]。我想添加另一个候选人:[DebuggerNonUserCode]。这与VS选项“仅启用我的代码”一起使用(请参阅http://blog.functionalfun.net/2008/05/debuggernonusercode-suppressing.html)。

因此,尽管[DebuggerHidden]绝不会在那里被关上,在接下来的周围用户代码,而不是报告它的构造异常突破,[DebuggerNonUserCode]可以让你忽略或根据您的VS调试设置构造断裂。只要设置“仅启用我的代码”,两个属性的行为方式应该是相同的。

假设MEF初始化在调试器隐藏的代码中完全处理,对于非MEF构造函数调用,调试器首次到达未标记为隐藏的环境函数时将中断。

+0

不是我所希望的,而是最接近问题的。谢谢。 – HCL

这听起来像只有你知道哪些组件是重要的,哪些不是。 您可能想要做一些事情,比如将组件初始化封装在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/

+0

THX,我会更深入了解它的明天。但我怀疑,它并不能帮助解决问题,我已经能够没有激活插件,这是不是我的问题(或待处理的问题)是,异常发生在模块的构造函数中,因此Visual Studio将在每个构造函数中中断,除非我禁用Visual中有关异常的中断行为Studio或[DebuggerHidden]/[DebuggerStepThroug] -attributes(thx grek40)。我认为解决问题的唯一方法就是将MEF类继承下来。 – HCL

+1

从这个描述中,它听起来像你的问题是,你不想让VS停在“一些例外”,当你把它附加到你的代码? – War

+0

FYI有没有办法让VS至“选择性忽视一些特定的例外”,但你可以告诉它忽略类型的异常(如你暗示你似乎已经知道了) – War

我可前往错DIRECTI对,但没有处理的情况下默认实现抽象工厂有帮助吗?

我用这个为我的依赖与团结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应用程序中注册新应用程序的组件。我从MEF导出依赖关系解析器接收到的每个部分都可以通过注入我的mvc控制器的构造函数来扩展。 在组件加载器中,我使用dll加载容器,并且可以通过在事实之后添加unity.config来扩展依赖关系。

Private Shared Sub RegisterDependencies(container As IUnityContainer) 
     'load services 
     ComponentLoader.LoadContainer(container, ".\\bin", "Service.dll") 

     'load config 
     'container.LoadConfiguration() 
    End Sub 
+0

感谢你好你的答案。我也想到了这一点,但是如果我想在调用方这一点,它只会推迟问题,如果我会在模块网站上做到这一点,我将不得不为每个模块写一个工厂(因为不同的构造函数参数),这是不需要的。还是我误解了你的主张? – HCL

的MEF中已经包括此为自MEF 6预览功能,这就是所谓的稳定的组成。即使未提供依赖关系,MEF也可以安全地启动。

简单地解决您的问题将是检查值是否实际上创建之前访问该值。

if(myLazy.IsValueCreated) 
    myLazy.Value // do something with the value, so the object gets composed 

您可以阅读更多关于它here

注:如果您有可选的依赖和系统可以在没有他们的工作,然后不要把参数空检查在构造函数。它将在构图期间使它们成为必需的依赖关系。

正如您已经提到的,当参数为null时,您不希望更改抛出异常的约定。那么如果你知道这个系统在没有这些依赖关系的情况下可以正常工作,那么你可以避免为这种依赖关系进行检查。

+0

嗨,感谢您的回答。听起来很有希望。但是我还没有完全理解它:懒惰{T}使得模块在以后加载。如果我会检查IsValueCreated,这将永远是假的,只要我没有访问的值(此看到我懒{}的唯一目的),也MEF不会尝试实例懒惰的,因为真正的对象【T}。如果我打电话给Value,我和以前一样。但也许我错过了这一点?你能进一步阐述一下吗? – HCL

+0

至于答案的注释部分:依赖关系不是可选的。这些模块是现有的,它们需要构造函数参数。因此,ArgumentNullException。最好的情况是,如果我能告诉MEF不尝试创建依赖项,如果导入构造函数需要可导出的依赖项,但其值现在为空。但是我没有找到这样的可能性。 – HCL

+0

我想我写得太快..你说得对懒惰不会做我期望的。我认为我们需要用于诊断的mefx库类。我会在周末更新我的答案,以包含更多细节。 – vendettamit