Что следует учитывать при выборе между ByRef и ByVal.
Я понимаю разницу между ними, но я не совсем понимаю, экономит ли ByRef ресурсы или нам даже нужно беспокоиться об этом в среде .Net.
Как выбрать между ними, если в конкретной ситуации функциональность не имеет значения?
Покажите, пожалуйста, синтаксис Java, и мы скажем, можете ли вы сделать то же самое на C#. Имейте в виду, что Java - это чисто передача по значению ...
На других языках в целях экономии ресурсов большие объекты могут передаваться по ссылке только для чтения в целях экономии ресурсов. Он действует как ссылка, переданная по значению, но не делает копию.
Да, но в Java нет ничего подобного ... поэтому я попросил пример Java.





ByVal должен быть вашим "по умолчанию". Используйте его, если у вас нет особой причины использовать ByRef
ByVal. Подробнее см. этот ответ.
Вот сбивающее с толку противоречие с той статьей, в которой говорится, что по умолчанию используется ByRef, но в качестве аргумента будет передаваться ссылка или значение, в зависимости от других факторов. связь
Я думаю, что это странный способ избежать вдаваться в подробности разницы между типы значений и ссылки.
Используйте «ByRef», только если параметр является «выходным» параметром. В противном случае используйте «ByVal». Использование «ByRef» для параметров, которые явно не должны возвращать значения, опасно и может легко вызвать ошибки.
Нет. Используйте «Out», если параметр должен быть «выходным» параметром. Используйте «ByRef», если параметр должен быть параметром «Ссылка».
Об этом много дезинформации. Главное, чтобы вы понимали разница между типами значений и ссылочными типами и разница между передачей по значению и передачей по ссылке.
Вы почти всегда хотите идти по цене. Передача по ссылке почти всегда означает «Я хочу вернуть более одного результата, а не просто добавляя элементы в переданный список». Классическим примером метода, использующего передачу по ссылке, является Int32.TryParse, где возвращаемое значение - успех / неудача, а проанализированное значение «возвращается» параметром out.
+1. Передача по ссылке и изменение внутри метода, который возвращает void, - это, на мой взгляд, распространенная «ошибка» - это вводит в заблуждение относительно того, что делает метод.
Многие разработчики по-прежнему склонны использовать этот шаблон - может быть, потому, что их опыт работы с C++ или COM, где ret val всегда были кодами ошибок и этот шаблон был необходим?
Передача объекта ByVal в .net не создает копию объекта и не потребляет больше ресурсов, чем ByRef. Указатель по-прежнему передается функции. Среда выполнения просто гарантирует, что вы не можете изменить указатель в своей функции и вернуть для него другое значение. Вы по-прежнему можете вносить изменения в значения внутри объекта, и вы увидите эти изменения вне функции. Вот почему ByRef используется так редко. Это необходимо только тогда, когда вы хотите, чтобы функция изменила фактический возвращаемый объект; следовательно, выходной параметр.
Это правда? Почему его отклонили? Возможно, я неправильно задал вопрос, потому что это больше похоже на ответ, который я искал.
Технически это правда, но вводит в заблуждение. При передаче объекта по Val, «объект» не копируется, но адрес объекта копируется и передается вызываемому методу. При передаче byRef адрес объекта НЕ копируется, адрес адресов передается.
Технически это не так, даже для классов. Но для типов значений это еще более неверно. - Для классов вы передаете КОПИЮ УКАЗАТЕЛЯ классу при передаче byval. Опять же, этот указатель КОПИРОВАННЫЙ. (Следовательно, если вы переназначаете указатель в вызываемой программе, вызывающая сторона не улавливает изменение.) Для типов значений, если вы передаете по значению, поскольку указателя нет, создается ПОЛНАЯ копия; Например, если вы передаете 200-байтовую структуру byval, 200 байтов копируется для каждого вызова - в отличие от byref, копируется только 4 (или 8, в зависимости от архитектуры) байтовый POINTER.
По умолчанию для ВСЕХ типов используется значение byValue, но важно понимать, что означают эти два параметра для «ссылочного типа» (класса), а не для типа значения. (структуры).
Для ссылочного типа, если вы объявляете переменную ссылочного типа в методе, эта переменная является ячейкой памяти в кадре стека метода. Его нет в куче. Когда вы инициализируете эту переменную (используя new или factory, что угодно), вы создали фактический объект в куче, и адрес этого объекта сохраняется в объявленной ссылочной переменной в кадре стека методов.
Когда вы передаете ссылочный тип другому методу с помощью Val, вы создаете копию адреса, хранящегося в стеке вызывающих методов, и передаете копию этого значения (адрес указателя) вызываемому методу, где она сохраняется в новой памяти. слот в стеке вызываемых методов. Внутри вызываемого метода новая клонированная переменная указывает прямо на тот же объект в куче. Таким образом, с его помощью можно изменить свойства одного и того же объекта. Но вы не можете изменить, на какой объект кучи указывает исходная ссылочная переменная (в стеке вызывающих методов). Если в вызываемом методе я напишу
myVar = new object();
Исходная переменная в вызывающем методе не изменится и укажет на новый объект.
Если я передаю ссылочный тип byRef, otoh, я передаю указатель на объявленную переменную в стеке вызывающих методов (который содержит указатель на объект в куче), следовательно, это указатель на указатель на объект. Он указывает на ячейку памяти в стеке вызывающих методов, которая указывает на объект в куче. Итак, теперь, если я изменю значение переменной в вызываемом методе, установив его на новый объект (), как указано выше, поскольку это «ссылка» на переменную в вызывающем методе, я фактически изменяю, какой объект переменная в вызывающем методе указывает на. Итак, после возврата вызываемого метода переменная в вызывающем методе больше не будет указывать на тот же исходный объект в куче.
Это, конечно, то, что я узнал в мире Java, но я не уверен, что это так в .Net?
Я не фанат Java, но слышал, что в Java даже не было типов значений ... Что каждая переменная была ссылочным типом ... Это неправильно?
Да это не так. В Java есть типы значений. Чего у него нет, так это типов значений, определяемых пользователем.
ах, значит, вы имеете в виду такие вещи, как int, short, ulong, decimal, char и т.д ... реализуются как типы значений в каждом кадре стека методов, но любой настраиваемый пользовательский тип реализуется как тип ref в куче?
Да, хотя имейте в виду, что типы значений также попадают в кучу как часть других объектов. См. pobox.com/~skeet/csharp/memory.html
да, то, что мы называем "полем" в .Net ... переменная, объявленная внутри типа (класса или структуры), который находится вне любого метода, свойства или конструктора ...
+1, потому что ответ чертовски уместен, учитывая, как был задан вопрос (и правильный) - однако я думаю, что спрашивающий хотел конкретно знать о типах значений в .NET.
FYI, в Java, да, есть типы значений для таких вещей, как int, short, double и т. д... есть также типы классов, такие как Integer, Double и т. Д ... в .NET int - это просто псевдоним для Int32, это тип значения с методами и т. д. ... в Java они совсем не совпадают; Integer - это класс, который обертывает int, который дает ему свойства (вы даже передаете int в конструктор). В .NET вы можете пойти дальше и сказать 42.ToString () - попробуйте сделать это на Java.
Значение ссылочного типа, находящегося в стеке или куче, не имеет значения. Это деталь реализации, которую можно изменить в любое время. Что важно, так это то, что на тот же объект создается другая ссылка, и она помещается в память (где бы она ни находилась), то есть передается копия REFERENCE. Для структур передается копия ОБЪЕКТА.
Пометка определенных аргументов как ByRef показывает пользователю вашей функции, что Переменная, назначенный этому аргументу **, будет изменен. ****
Если вы используете ByRef для всех аргументов, не будет способа узнать, какие переменные изменяются функцией, а какие просто читаются. (кроме заглядывания внутрь источника функции!)
Я бы сказал, что ByRef никогда не следует использовать - это плохая практика. Я бы применил это даже к его типичному варианту использования, когда функция может возвращать несколько значений (через параметры ByRef). Было бы лучше, если бы функция вернула структурированный ответ, включающий эти несколько возвращаемых значений. Это более ясно и очевидно, если функция возвращает значения только через свой оператор return.
Ага, совершенно верно. Включение его в .NET было серьезной ерундой.
Я не согласен. Это может быть чрезвычайно полезно для таких вещей, как классический метод обмена: «Swap <T> (ref T a, ref T b) where T: struct {...}» (извиняюсь, если я ошибся в синтаксисе)
Как можно использовать Threading.Interlocked.Increment и других подобных участников без ByRef?
Это именно то, что вам нужно, когда это нужно. Однако в большинстве случаев вы этого не делаете. Поэтому следует использовать только тогда, когда вам это особенно нужно.
Полностью согласен, функция с ByRef - очень плохая практика. И это довольно странно, особенно для тех, кто имеет опыт функционального программирования.
Проектное решение определяет, нужно ли вам использовать ByRef. Я программировал на .NET с самого начала, и я никогда не принимал решения, которое заставило бы меня в этом нуждаться.
Не могли бы вы использовать ByRef при предоставлении параметров для функции, вызывающей базу данных, которая возвращает количество найденных записей? Записи, которые вы получаете обратно, находятся в параметре ByRef.
Согласно Microsoft, выбор ByVal или ByRef может повлиять на производительность для достаточно больших значений (см. Передача аргументов по значению и по ссылке (Visual Basic)):
Performance. Although the passing mechanism can affect the performance of your code, the difference is usually insignificant. One exception to this is a value type passed ByVal. In this case, Visual Basic copies the entire data contents of the argument. Therefore, for a large value type such as a structure, it can be more efficient to pass it ByRef.
[курсив добавлен].
Sub last_column_process()
Dim last_column As Integer
last_column = 234
MsgBox last_column
trying_byref x:=last_column
MsgBox last_column
trying_byval v:=last_column
MsgBox last_column
End Sub
Sub trying_byref(ByRef x)
x = 345
End Sub
Sub trying_byval(ByRef v)
v = 555
End Sub
Я постараюсь упростить эту путаницу. В основном у вас есть 4 варианта:
Некоторые говорят, что никогда следует использовать byRef. Хотя они технически верны, одно можно сказать наверняка. Вы должны НИКОГДА использовать слово никогда. Если вы разрабатываете систему с нуля, следует избегать использования byRef любой ценой. Его использование обнажает конструктивный недостаток. Однако работа над существующей системой может не обеспечить такой гибкости, чтобы реализовать хороший дизайн. Иногда вы должны прийти к согласию, например, используя byRef. Например, если вы можете получить исправление за 2 дня с помощью byRef, тогда это может быть предпочтительнее заново изобретать колесо и потратить неделю на то же исправление, чтобы избежать использования byRef.
Резюме:
Не уверен, что правильно задал вопрос. Существует ли эквивалент .Net для передачи чего-то ByRef как ReadOnly (как в Java)? Чтобы сэкономить ресурсы?