我遇到了同样的问题,解释了 here ,但正在迭代EnvDTE.Processes
。
在我链接用户的问题@ Plutonix 确认这是一个错误警告,我认为他参考obj.Getenumerator()
提及所以我认为我的问题将被视为错误但是,如果这是一个错误的警告,我想知道的不仅仅是一个肯定,而是说这是一个错误的警告。
这是警告:
CA2202不要多次处置对象Object ' procs.GetEnumerator()'在方法中可以多次丢弃 ' DebugUtil.GetCurrentVisualStudioInstance()&#39 ;.为了避免产生 System.ObjectDisposedException你不应该调用Dispose 一次在物体上:线条: 214 Elektro.Application.Debugging DebugUtil.vb 214
这是代码,procs
对象是警告中涉及的对象,但我没有看到任何一次性对象:
Public Shared Function GetCurrentVisualStudioInstance() As DTE2
Dim currentInstance As DTE2 = Nothing
Dim processName As String = Process.GetCurrentProcess.MainModule.FileName
Dim instances As IEnumerable(Of DTE2) = DebugUtil.GetVisualStudioInstances
Dim procs As EnvDTE.Processes
For Each instance As DTE2 In instances
procs = instance.Debugger.DebuggedProcesses
For Each p As EnvDTE.Process In procs
If (p.Name = processName) Then
currentInstance = instance
Exit For
End If
Next p
Next instance
Return currentInstance
End Function
PS:请注意,代码块取决于其他成员,但它们与此问题无关。
答案 0 :(得分:5)
简短版本:对我来说,这看起来像代码分析组件中的错误。
很长的版本(嘿,你哄我花了我下午和晚上的大部分时间来解读这个,所以你不妨花一点时间阅读它:))...
我做的第一件事就是看IL。与我的猜测相反,它确实不在同一个对象上包含对Dispose()
的多次调用。这个理论非常重要。
但是,该方法包含对Dispose()
的两个单独调用,仅适用于不同的对象。到这个时候,我已经确信这是一个错误。我已经看到在处理一个类实例"拥有的相关类时触发CA2202的提及。另一个类的实例,并且两个实例都被处理掉了。虽然不方便且值得压制,但在这些情况下警告似乎是有效的;其中一个对象真的被处理了两次。
但在这种情况下,我有两个独立的IEnumerator
个对象;一个人不拥有,也没有与另一个人有关。处置一个不会处置另一个。因此,代码分析是错误的警告。但具体是什么令人困惑呢?
经过多次实验,我想出了这个近乎极少的代码示例:
Public Class A
Public ReadOnly Property B As B
Get
Return New B
End Get
End Property
End Class
Public Interface IB
Function GetEnumerator() As IEnumerator
End Interface
Public Class B : Implements IB
Public Iterator Function GetEnumerator() As IEnumerator Implements IB.GetEnumerator
Yield New C
End Function
End Class
Public Class C
Dim _value As String
Public Property Value As String
Get
Return _value
End Get
Set(value As String)
_value = value
End Set
End Property
End Class
Public Shared Function GetCurrentVisualStudioInstance2() As A
For Each a As A In GetAs()
For Each c As C In a.B
If (c.Value = Nothing) Then
Return a
End If
Next c
Next a
Return Nothing
End Function
Public Shared Iterator Function GetAs() As IEnumerable(Of A)
Yield New A()
End Function
这会产生您在其他代码示例中看到的相同的虚假CA2202。有趣的是,对接口IB
的声明和实现的微小改动导致警告消失:
Public Interface IB : Inherits IEnumerable
End Interface
Public Class B : Implements IB
Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Yield New C
End Function
End Class
不知何故,代码分析因IEnumerable
的非GetEnumerator()
实现而感到困惑。 (更奇怪的是,您使用的实际类型,DTE API中的Processes
接口,都继承IEnumerable
和声明自己的{{1}方法......但后者是代码分析混淆的根源,而不是组合。)
有了这个,我试图在C#中重现这个问题,发现我做不到。我编写了一个C#版本,其结构与VB.NET版本中的类型和方法完全相同,但它在没有警告的情况下通过了代码分析。所以我再次看了IL。
我发现C#编译器生成的代码与VB.NET编译器非常相似,但不完全相同。特别是,对于保护每个循环返回的GetEnumerator()
的{{1}} / try
块,这些循环的所有初始化都在外部执行 {{阻止,而在VB.NET版本中,初始化是在内部执行的。
显然,这也足以阻止代码分析对一次性物品的使用感到困惑。
鉴于它似乎是VB.NET的finally
实现与嵌套循环的结合,一种解决方法就是以不同的方式实现该方法。无论如何我更喜欢LINQ语法,这里是你的方法的LINQified版本,它编译时没有代码分析警告:
IEnumerator
完整性,C#版本(因为所有这些代码都是在C#实现转换为VB.NET后开始扩展以处理"当前实例"案例):
try