Ele*_*ios 3 vb.net code-analysis visual-studio
我遇到了同样的问题,这里解释但是迭代了EnvDTE.Processes.
在我链接的问题中,用户@ Plutonix确认这是一个虚假的警告,我认为他提到了这obj.Getenumerator()一点,所以我认为我的问题也将被视为虚假警告,但是,如果这是一个虚假的警告,我想知道的不仅仅是一种肯定,而是说它是一种虚假的警告.
这是警告:
CA2202不要多次处理对象对象'procs.GetEnumerator()'可以在方法'DebugUtil.GetCurrentVisualStudioInstance()'中多次处理.为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose:Lines: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
Run Code Online (Sandbox Code Playgroud)
PS:请注意,代码块取决于其他成员,但它们与此问题无关.
简短版本:对我来说,这看起来像代码分析组件中的错误.
长版本(嘿,你哄我花了我下午和晚上的大部分时间来解读这个,所以你不妨花一点时间阅读它:))...
我做的第一件事就是看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
Run Code Online (Sandbox Code Playgroud)
这会产生与您在其他代码示例中看到的相同的虚假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
Run Code Online (Sandbox Code Playgroud)
不知何故,代码分析正在被非IEnumerable实现的混淆GetEnumerator().(更奇怪的是,您使用的实际类型,ProcessesDTE API中的接口,都继承IEnumerable 并声明了自己的GetEnumerator()方法......但后者是代码分析混淆的根源,而不是组合).
有了这个,我试图用C#重现这个问题,发现我做不到.我编写了一个C#版本,其结构与VB.NET版本中的类型和方法完全相同,但它在没有警告的情况下通过了代码分析.所以我再次看了IL.
我发现C#编译器生成的代码与VB.NET编译器非常相似,但不完全相同.特别是,对于保护每个循环返回的try/ finally块,IEnumerator这些循环的所有初始化都在块外执行try,而在VB.NET版本中,初始化在内部执行.
显然,这也足以阻止代码分析对一次性对象的使用感到困惑.
鉴于它似乎是VB.NET的实现For Each和嵌套循环的组合,一种解决方法是以不同方式实现该方法.无论如何我更喜欢LINQ语法,这里是你的方法的LINQified版本,它编译时没有Code Analysis警告:
Public Shared Function GetCurrentVisualStudioInstance() As DTE2
Dim processName As String = Process.GetCurrentProcess.MainModule.FileName
Return GetVisualStudioInstances.FirstOrDefault(
Function(instance)
Return instance.Debugger.DebuggedProcesses.Cast(Of EnvDTE.Process).Any(
Function(p)
Return p.Name = processName
End Function)
End Function)
End Function
Run Code Online (Sandbox Code Playgroud)
而且为了完整性,还有C#版本(因为所有这些代码都是在C#实现转换为VB.NET然后扩展以处理"当前实例"的情况下启动的):
public static DTE2 GetCurrentVisualStudioInstance()
{
string processName = Process.GetCurrentProcess().MainModule.FileName;
return GetVisualStudioInstances()
.FirstOrDefault(i => i.Debugger.DebuggedProcesses
.Cast<EnvDTE.Process>().Any(p => p.Name == processName));
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
294 次 |
| 最近记录: |