对象初始值设定项和属性可以抛出exception时的Dispose

我有以下设置:

public class SomeClass { private DirectoryEntry _root; private DirectorySearcher _searcher; public SomeClass() { _root = new DirectoryEntry("ldap://bla"); _searcher = new DirectorySearcher(_root) { PageSize = int.MaxValue, SizeLimit = int.MaxValue } } } 

我使用int.MaxValue的原因是因为在这种情况下我知道我将超过默认值,但数字永远不会太大,所以我对这一点很好。

但是,如果我打开代码分析Microsoft Basic正确性规则,它会抱怨:

警告2 CA2000:Microsoft.Reliability:在方法’SomeClass.SomeClass()’中,对象’ g_ initLocal0’未沿所有exception路径放置。 在对对象’ g _initLocal0’的所有引用都超出范围之前, 调用System.IDisposable.Dispose

问题是PageSize和SizeLimit可以抛出exception,如果发生这种情况, G__initLocal0对象就不会被处理掉(即使_searcher被处理掉了)。 他们可以抛出的例外情况是,如果你将它们分配给负数,这在这里不会发生,但它仍然会抱怨。

接下来,我使用常规赋值语句在对象intitializer外部设置属性,但是然后ReSharper抱怨告诉我应该使用Initializer。 我可以压制ReSharper,但我喜欢想办法让事情发挥作用而不增加抑制。

所以我想我必须抓住错误,如果可能的话,我不喜欢在构造函数中捕获错误,所以我创建了一个名为Searcher的属性,如下所示:

 private DirectorySearcher _searcher; public DirectorySearcher Searcher { get { if (_searcher != null) return _searcher; var searcher = new DirectorySearcher(); try { searcher.PageSize = int.MaxValue; searcher.SizeLimit = int.MaxValue; _searcher = searcher; } catch { searcher.PageSize = 1000; searcher.SizeLimit = 1000; } finally { searcher.Dispose(); } return _searcher; } } 

现在代码分析,一切都很开心,但我对解决方案不满意。

任何提示?

你现在做事的方式可能会让每个人都开心,但你却无法工作。 您将在Searcher属性中返回已处理的DirectorySearcher

我只是这样做:

 public SomeClass() { _root = new DirectoryEntry("ldap://bla"); try { _searcher = new DirectorySearcher(_root); _searcher.PageSize = 1000; _searcher.SizeLimit = 1000; } catch { if (_searcher != null) { _searcher.Dispose(); } throw; } 

}

我没有看到在构造函数中使用try-catch块有什么问题。

在构造IDisposable对象时,我不建议使用属性初始化程序语法,因为如果属性初始化抛出,则无法正常处理它们。

问题是编译器有效地生成:

 public class SomeClass { private DirectoryEntry _root; private DirectorySearcher _searcher; public SomeClass() { _root = new DirectoryEntry("ldap://bla"); var temp = new DirectorySearcher(_root); temp.PageSize = int.MaxValue; temp.SizeLimit = int.MaxValue; _searcher = temp; } } 

您可以通过不为_searcher使用较新的属性初始化程序语法来避免这种情况,以便在设置属性之前确保将其正确分配给字段,请参阅using-block中的对象初始值设定项生成代码分析警告CA2000 。

这里有第二个问题,即如果在构造SomeClass期间出现错误,调用代码将无法处理SomeClass ,因此无法处理_root_searcher ,请参阅失败的初始化程序或构造函数中的处理IDisposable 。

如果在SomeClass实例的整个生命周期中需要_searcher,SomeClass应该实现IDisposable并在Dispose中配置_searcher。

请参阅http://msdn.microsoft.com/de-de/library/system.idisposable.aspx 。