.NET: Передача по ссылке - ложь? - PullRequest
0 голосов
/ 05 сентября 2018

Я столкнулся с интересным случаем, когда передача по ссылке не работает в VB.NET. Ниже приведен пример кода, чтобы вы могли с ним поиграть. Может кто-нибудь объяснить это явление. Это предназначено, или ошибка с языком / компилятором?

Что я вижу в этом коде, так это то, что показания «После увеличения» такие же, как и «Перед приращением».

Public Class Wrapper
    Public Property Value As Integer
End Class

Sub Main()

    Dim rand As New Random()

    Dim w As New Wrapper()
    w.Value = rand.Next()
    Console.WriteLine("Before Increment: {0}", w.Value)

    Try
        Increment(w.Value)
    Catch ex As Exception
    End Try

    Console.WriteLine("After Increment: {0}", w.Value)

    Console.ReadLine()
End Sub

Public Sub Increment(ByRef i As Integer)
    i += 1
    Throw New Exception()
End Sub

1 Ответ

0 голосов
/ 06 сентября 2018

Я столкнулся с интересным случаем, когда передача по ссылке не работает в VB.NET.

Действительно, это довольно интересный случай.

Я предоставил вам пример кода ниже, чтобы вы все могли поиграть. Может кто-нибудь объяснить это явление.

Да.

Это предназначено, или ошибка с языком / компилятором?

Такое поведение разработано и не является ошибкой. Вы не должны писать код VB, подобный этому . Если вам больно, когда вы делаете это, прекратите это делать .

Все это имеет смысл, но вы должны понимать логику этого. Следуйте

  • byref - это псевдоним переменной. То есть, когда вы передаете переменную методу, который берет byref, формальный параметр становится псевдонимом для переменной. У нас есть одна переменная с двумя именами .
  • Свойство не является переменной. Свойство - это пара методов: получатель и установщик. Свойство может быть поддержано переменной, но свойство не является переменной . Это геттер, который производит значение , и сеттер, который получает значение . Убедитесь, что вы четко понимаете разницу между значениями и переменными. Переменные содержат значения.
  • Что произойдет, если вы попытаетесь передать свойство методу, ожидающему параметр byref? В C # это незаконно. В VB компилятор генерирует для вас временную переменную и передает ее по ссылке, используя семантику копирование-в-копирование . То есть ваша программа эквивалентна:

Try
    Dim Temp As Integer
    Temp = w.Value  ' copy-in
    Increment(Temp) ' make an alias to Temp
    w.Value = Temp  ' copy-out
Catch ex As Exception
End Try

Теперь должно быть очевидно, почему ваша программа имеет такое же поведение. Бросок происходит перед копированием .


Люди часто говорят, что C # и VB - это "один и тот же язык" с разным синтаксисом, и в этом есть доля правды. Однако примеры, демонстрирующие небольшие различия, показывают, что языки имеют разные принципы проектирования. Не случайно C # и VB отличаются обработкой значений, переданных ref!

Принципы проектирования C # включают в себя то, что компилятор должен сообщать вам, когда код выглядит неправильно, и, в частности, компилятор не должен «замазывать» проблемы, угадывая, что вы имели в виду, и испуская код для своего рода сортировки, заставляет его работать большую часть время. Команда разработчиков видит отношение программистов на C # как «компилятор - мой друг, который говорит мне, когда я ошибаюсь, чтобы я мог улучшиться».

Принципы проектирования VB включают в себя то, что код, вероятно, работает просто отлично, и что если есть что-то, что выглядит не совсем правильно, выясните, что имел в виду пользователь, и заставьте его работать, даже если это означает введение кода, который, скажем, не ' t сохранить идентичность объекта или добавить скрытое копирование в копирование или что-то еще. Команда разработчиков видит отношение программистов на VB как «компилятор слишком часто стоит у меня на пути; я выразил намерение, чтобы он работал».

Оба принципа разработки абсолютно разумны, и для каждого из них существуют большие группы разработчиков. Я думаю, что очень приятно, что Microsoft потратила десятилетия, удваивая затраты на развитие языка, чтобы у разработчиков была возможность выбрать язык, который соответствует их темпераменту.

Тем не менее, в C # существуют ситуации, когда компилятор делает что-то подобное: создает временную переменную, присваивает ей значение, а затем передает переменную с помощью ref.

Задача: создать программу, которая демонстрирует этот факт.

Подсказка № 1: изменяемые структуры являются плохой практикой в ​​C # по определенной причине.

Подсказка # 2: при каких обстоятельствах переменная рассматривается как значение в C #?

...