繁体   English   中英

C#和VB中的VB编译器和/或IntelliSense中的错误WRT超出范围的属性设置器和ByRef fn()参数

[英]Bug in VB compiler and/or IntelliSense in both C# and VB WRT out-of-scope Property Setters and ByRef fn() Parameters

我已经注意到Visual Studio 2008(.NET 3.5)和Visual Studio 2010 Beta 2(.NET 4.0)中的一些看似奇怪的问题。 这些问题也可能存在于先前版本中。 也许它们不是问题,但不管怎样,我想在我提交Microsoft Connect报告之前看看是否有合理的解释。

安装程序(在VB中,C#结果不同,后面包含在帖子中):

Public Class SomeClass
    Public Property SomeProperty() As String
        Get
            Return String.Empty
        End Get
        Set(ByVal value As String)
        End Set
    End Property
End Class

Public Class SomeOtherClass
    Public Sub New()
        Dim sc As New SomeClass()
        Me.SomeFunction(sc.SomeProperty)
    End Sub

    ''' <summary>The param as Object fn()</summary> '''
    Public Sub SomeFunction(ByVal param As Object)
    End Sub

    ''' <summary>The param as T fn()</summary> '''
    Public Sub SomeFunction(Of T)(ByRef param As T)
    End Sub
End Class

在这种情况下,从IntelliSense的角度来看, Me.SomeFunction(sc.SomeProperty)调用如下所示:
替代文字
并且,毫不奇怪,这也是在运行时调用的。

所以,我想我的第一个问题是, 为什么ByRef模板化的过载版本的函数选择超过ByVal Object的函数重载版本? 我的猜测是编译器和IntelliSense只是偏向模板化版本而不是非模板化版本。 在运行时,它实际上是被调用函数的ByRef模板化版本。 (这不是缺陷,这只是个人想知道的问题。)

现在,稍微更改SomeProperty属性,使setter现在是私有的:

Public Property SomeProperty() As String
    Get
        Return String.Empty
    End Get
    Private Set(ByVal value As String)
    End Set
End Property

一旦执行此操作, Me.SomeFunction(sc.SomeProperty)行就会发生以下情况:
替代文字

在这种情况下,IntelliSense建议调用函数的ByVal Object重载版本,但是错误消息是the 'Set' accessor of property 'SomeProperty' is not accessiblethe 'Set' accessor of property 'SomeProperty' is not accessible表明编译器仍然期望调用ByRef模板化版。 所以,这是我的第二个问题 为什么Intellisense声称有一件事,而VB编译器显然正在尝试别的东西? 这似乎打破了我。 或者我错过了什么?

如果不是在SomeProperty上使用私有setter而是将属性简单地标记为ReadOnly并且删除了setter部分,那么函数的ByRef模板化版本将在IntelliSense中显示并在运行时调用(没有运行时错误)。 所以这引出了我的第三个问题为什么VB编译器将ByRef params的输入处理为ReadOnly和非ReadOnly属性不同,但是在VB中有一个超出范围的setter就SomeFunction(Of T)而言(...)在其当前范围内,该属性应该像ReadOnly一样,并且我希望它可以被调用,就好像该属性实际上是ReadOnly一样。 但相反,它会产生构建错误。

与问题3相关,进行完全相同的设置 (使用私有设置器),C#具有我期望的结果。 替代文字
在这里,您可以看到IntelliSense声称正在调用函数的SomeFunction(Object)重载并且没有构建错误。 在运行时,实际上调用了SomeFunction(Object)版本。 那么,为什么在VB.NET情况下调用的SomeFunction(Object)版本不一样呢? 为什么VB.NET仍然认为需要调用SomeFunction(Of T)(ByRef T)版本? 看起来IntelliSense在C#和VB.NET中正确地指出它,C#编译器正在做正确的事情,但VB.NET编译器仍然相信它应该调用ByRef模板化版本。 对我来说,似乎C#编译器正在选择一个重载,而VB.NET编译器正在选择一个不同的重载,在完全相同的情况下。 我错了吗?

关于你的第三个问题:

为什么VB编译器将ByRef参数的输入处理为ReadOnly与非ReadOnly的属性不同,但在VB中具有超出范围的setter

在CLR中,无法将属性作为ByRef传递。 然而,VB.NET团队认为这将是有用的并实现了一种解决方法。 在内部,

Me.SomeFunction(sc.SomeProperty)

被转换为

Dim vbTemp = sc.SomeProperty
Me.SomeFunction(vbTemp)

它被称为Do not Copy Back ByRef并用于例如Read-Only属性,或者

Dim vbTemp = sc.SomeProperty
Me.SomeFunction(vbTemp)
sc.SomeProperty = vbTemp

它被称为Copy Back ByRef ,用于包含getter和setter的属性。 jaredpar的WebLog中解释了所有这些(以及一些更复杂的情况) :ByRef的许多案例

现在,您要说的是当setter超出范围时,应该执行Do not Copy Back ByRef 但是,这会导致行为不一致: SomeFunction(sc.SomeProperty) SomeClass 内部 sc.SomeProperty时更新sc.SomeProperty ,但同一行代码在外部调用时会默默地不更新属性(因为setter超出了范围) 。


关于你的第一个和第二个问题:

为什么函数的ByRef模板化过载版本超过了函数的ByVal Object重载版本? 我的猜测是编译器和IntelliSense只是偏向模板化版本而不是非模板化版本。

他们喜欢模板版本而不是需要扩展到Object 重载决策在Visual Basic语言规范的第11.8.1节中有详细描述。

为什么Intellisense声称有一件事,而VB编译器显然正在尝试别的东西?

对我来说看起来像个错误。

如果他们完全有可能选择不同的版本 - 重载分辨率是一个复杂的区域,在规范文档中详细定义。 例如,您需要指定考虑使用泛型的顺序,使用隐式案例/转换/装箱等。

另外 - 请记住,在C#中ref必须是显式的 ,因此ref版本甚至不是代码中的有效重载。 在VB中它是隐式的,并且(通过通用版本)可以使用完全匹配而无需任何转换/强制转换等。

令人困惑的是,可以可访问性检查之前进行重载解析,因此private (自身)并不令人惊讶。

我也并不认为智能感知不一定定义实际上是被调用的版本-刚好过载S中的使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM