我有以下设置:
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基本正确性规则,它会抱怨:
警告2 CA2000:Microsoft.Reliability:在方法'SomeClass.SomeClass()'中,对象'<> g_ initLocal0'未沿所有异常路径放置。在对对象'<> g _initLocal0'调用System.IDisposable.Dispose之前,对它的所有引用都超出了范围。
问题是PageSize和SizeLimit可以抛出异常,如果发生这种情况,G__initLocal0
对象就不会被处理掉(即使_searcher
被处置掉了)。他们可以抛出的例外情况是,如果你将它们分配给负数,这在这里不会发生,但它仍然会抱怨。
接下来,我使用常规赋值语句在对象intitializer外部设置属性,但是然后ReSharper抱怨告诉我应该使用Initializer。我可以压制ReSharper,但我喜欢想办法让事情发挥作用,而不会增加抑制。
所以我想我必须抓住错误,如果可能的话,我不喜欢我的构造函数中的catch错误,所以我创建了一个名为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;
}
}
现在代码分析,一切都很开心,但我对解决方案一点都不满意。
任何提示?
答案 0 :(得分:7)
问题是编译器正在有效地生成:
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使用较新的属性初始化程序语法来避免这种情况,以便在设置属性之前确保将其正确分配给字段,请参阅Object initializers in using-block generates code analysis warning CA2000。
这里存在第二个问题,即如果在构造SomeClass
期间出现错误,则调用代码将无法处置SomeClass
,因此无法处置_root
}或_searcher
,请参阅Handling IDisposable in failed initializer or constructor。
答案 1 :(得分:4)
现在你做事的方式可能会让每个人都开心,但你却无法工作。您将在DirectorySearcher
媒体资源中退回已处置的Searcher
。
我只是这样做:
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
对象时,我不建议使用属性初始化程序语法,因为如果属性初始化抛出,则无法正常处理它们。
答案 2 :(得分:0)
如果在SomeClass实例的整个生命周期中需要_searcher,SomeClass应该实现IDisposable并在Dispose中处理_searcher。
请参阅http://msdn.microsoft.com/de-de/library/system.idisposable.aspx。