Ошибка в компиляторе VB и / или IntelliSense как в C #, так и в VB WRT. Установщики свойств вне области и параметры ByRef fn () - PullRequest
4 голосов
/ 24 января 2010

Я заметил некоторые, казалось бы, странные проблемы в 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

В этом случае вызов Me.SomeFunction(sc.SomeProperty) с точки зрения IntelliSense выглядит следующим образом:
alt text
и, что неудивительно, это также то, что называется во время выполнения.

Итак, я думаю, первый вопрос , который у меня есть, , почему была выбрана версия функции ByRef с перегрузкой, выбранная из версии функции перегрузки ByVal Object? Я предполагаю, что что компилятор и IntelliSense просто предпочитают шаблонные версии по сравнению с не шаблонными версиями. Во время выполнения вызывается только шаблонная версия функции ByRef. (Это не дефект, это просто личный вопрос, который нужно знать.)

Теперь внесите небольшое изменение в свойство SomeProperty, чтобы установщик стал приватным:

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) произойдет следующее:
alt text

В этом случае IntelliSense предполагает, что вызывается версия функции ByVal, перегруженная объектом, однако появляется сообщение об ошибке the 'Set' accessor of property 'SomeProperty' is not accessible, указывающее, что компилятор все еще ожидает вызова шаблонной версии ByRef. Итак, это мой второй вопрос . Почему Intellisense требует одного, а VB-компилятор явно пытается что-то другое? Мне кажется, что это не так. Или я что-то упустил?

Если вместо SomeProperty имеется закрытый установщик, но вместо этого свойство просто помечено как ReadOnly, а установщик удален, то шаблонная версия ByRef функции отображается в IntelliSense и вызывается во время выполнения (без ошибок во время выполнения) ). Таким образом, это приводит меня к моему третьему вопросу , , почему компилятор VB обрабатывает входные данные для параметров ByRef для свойств, которые являются ReadOnly и not-ReadOnly, но имеют установщик вне области видимости в VB Что касается SomeFunction (Of T) (...), то в его текущей области это свойство должно быть таким, как если бы оно было ReadOnly, и я ожидаю, что оно будет вызываться так же, как если бы это свойство было на самом деле ReadOnly. Но вместо этого он выдает ошибку сборки.

В связи с третьим вопросом, при выполнении точно такой же настройки (с частным сеттером), C # имеет ожидаемый результат. alt text
Здесь вы можете видеть, что 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 выбирает другую перегрузку в точно такой же ситуации. Я не прав?

Ответы [ 2 ]

6 голосов
/ 24 января 2010

По поводу вашего третьего вопроса:

Почему компилятор VB обрабатывает входные данные для параметров ByRef, отличающиеся для свойств, которые являются ReadOnly и not-ReadOnly, но имеют установщик вне области действия в VB

В CLR невозможно передать свойство как ByRef. Однако команда VB.NET решила, что это будет полезно, и применила обходной путь. Внутренне

Me.SomeFunction(sc.SomeProperty)

конвертируется в

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

, который называется Не копировать назад ByRef и используется, например, для прав доступа только для чтения, или

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

, который называется Copy Back ByRef и используется для свойств, содержащих как геттер, так и сеттер. Все эти вещи (и несколько более сложных случаев) объясняются в jaredpar's WebLog: Много случаев ByRef .

Теперь вы говорите, что когда сеттер находится вне области видимости, следует выполнить Не копировать назад ByRef . Однако это может привести к противоречивому поведению: SomeFunction(sc.SomeProperty) будет обновлять sc.SomeProperty при вызове внутри из SomeClass, но та же строка кода без вывода сообщений не будет обновлять свойство, когда вызывается снаружи (потому что сеттер находится вне области видимости).


О вашем первом и втором вопросе:

Почему шаблонная версия функции перегрузки ByRef была выбрана вместо версии функции ByVal Object с перегрузкой? Я предполагаю, что компилятор и IntelliSense просто предпочитают шаблоны по сравнению с версиями без шаблонов.

Они предпочитают шаблонные версии по сравнению с версией, которая потребует расширения до Object. Разрешение перегрузки подробно описано в главе 11.8.1 Спецификация языка Visual Basic .

Почему Intellisense требует одного, а VB-компилятор явно пытается что-то другое?

Выглядит как ошибка для меня.

0 голосов
/ 24 января 2010

Если вполне возможно, что они выбирают разные версии - разрешение перегрузки является сложной областью, которая детально определена в технических документах. Например, вам нужно указать, в каком порядке рассматривать использование обобщений, использование неявных случаев / преобразований / бокса и т. Д.

Также помните, что в C # ref должно быть явным , поэтому версия ref даже не является допустимой перегрузкой из кода. В VB это неявно, и (через универсальную версию) может использовать точное совпадение без каких-либо преобразований / приведений / и т.д.

Может показаться, что разрешение перегрузки приходит до проверки доступности, поэтому вещь private (сама по себе) не удивительна.

Я также не думаю, что intellisense обязательно определяет версию, фактически являющуюся вызванной - только перегрузка s , которая доступна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...