使用全局高速缓存时,如何修复CA2000 IDisposable C#编译器警告

CA2000是关于IDisposable接口的警告:

CA2000:Microsoft.Reliability:在方法’ImportProcessor.GetContext(string)’中,在对所有引用超出范围之前,在对象’c’上调用System.IDisposable.Dispose。

我的方法用于存储上下文缓存,如下所示:

public class RegionContext : IDisposable { /* Implement Dispose() here */ } private Dictionary contextCache = new ..... (); public RegionContext GetContext(string regionCode) { RegionContext rc = null; if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc)) { rc = new RegionContext(regionCode); this.contextCache.Add(regionCode.ToUpper(), rc); } return rc; } 

你会在哪里使用修复此编译器警告的using()语句?

我的外部类实际上在自己的实现中迭代并处理contextCache中的内容。 我要压制它,还是有办法正确摆脱这个警告?

只要您具有IDisposable的返回值并且不处理方法抛出exception的情况,就会出现此CA2000警告。 在那种情况下,调用者将无法获得对象的有效实例,因此无法处置它。 所以你必须这样做。

我假设如果你成功地将它从缓存中拉出来,你将不想处置该对象。 在这种情况下,您需要执行以下操作以确保您可能在本地创建的对象在所有情况下都处理掉:

 public RegionContext GetContext(string regionCode) { RegionContext temp = null; RegionContext rc = null; try { if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc)) { temp = new RegionContext(regionCode); this.contextCache.Add(regionCode.ToUpper(), temp); rc = temp; temp = null; } return rc; } finally { if ( temp != null ) { temp.Dispose(); } } } 

CA2000在这里抱怨的是,如果在尝试将其添加到缓存时出现exception,则该变量可能在未处置状态下“孤立”。 要彻底解决问题,可以按如下方式添加try / catch(仅使用newContext变量以便CA2000可以检测到修复):

 public RegionContext GetContext(string regionCode) { RegionContext rc = null; if (!this.contextCache.TryGetValue(regionCode.ToUpper(), out rc)) { RegionContext newContext = new RegionContext(regionCode); try { this.contextCache.Add(regionCode.ToUpper(), newContext); } catch { newContext.Dispose(); throw; } rc = newContext; } return rc; } 

就个人而言,在大多数情况下,我发现这种事情有些荒谬,但是ymmv ……

转换为VB.Net时,Michael的解决方案似乎不起作用。 在VS 2017下测试了以下两个function:

  Public Function OpenStream(ByVal filePathName As String) As System.IO.FileStream Dim fileStream As System.IO.FileStream = Nothing Dim tempFileStream As System.IO.FileStream = Nothing If Not String.IsNullOrWhiteSpace(filePathName) Then Try tempFileStream = New System.IO.FileStream(filePathName, System.IO.FileMode.Open, System.IO.FileAccess.Read) fileStream = tempFileStream Catch tempFileStream?.Dispose() Throw End Try End If Return fileStream End Function Public Function OpenReader(ByVal filePathName As String) As System.IO.BinaryReader If String.IsNullOrWhiteSpace(filePathName) Then Throw New ArgumentNullException(NameOf(filePathName)) If Not System.IO.File.Exists(filePathName) Then Throw New System.IO.FileNotFoundException("Failed opening a binary reader -- file not found.", filePathName) Dim tempReader As System.IO.BinaryReader = Nothing Dim reader As System.IO.BinaryReader = Nothing Dim stream As IO.FileStream = Nothing Try stream = Methods.OpenStream(filePathName) tempReader = New System.IO.BinaryReader(stream) reader = tempReader Catch stream?.Dispose() tempReader?.Dispose() Throw End Try Return reader End Function