У меня есть объект, который является моим состоянием в памяти программы, а также есть некоторые другие рабочие функции, которым я передаю объект для изменения состояния. Я передал его по ссылке в рабочие функции. Однако я наткнулся на следующую функцию.
byte[] received_s = new byte[2048];
IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
EndPoint remoteEP = (tmpIpEndPoint);
int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP);
Это меня смущает, потому что оба received_s
и remoteEP
возвращают вещи из функции. Почему remoteEP
нуждающиеся ref
и received_s
не делает?
Я также программист на переменном языке, поэтому у меня проблема с получением указателей из головы.
Изменить: похоже, что объекты в C # являются указателями на объект под капотом. Поэтому, когда вы передаете объект функции, вы можете затем изменять содержимое объекта с помощью указателя, и единственное, что передается в функцию, - это указатель на объект, поэтому сам объект не копируется. Вы используете ref или out, если хотите иметь возможность выключить или создать новый объект в функции, который похож на двойной указатель.
if (int.TryParse(text, out int value)) { ... use value here ... }
Подумайте о параметре без ссылки как о указателе, а о параметре ref как о двойном указателе. Это помогло мне больше всего.
Практически никогда не следует передавать значения по ссылке. Я подозреваю, что, если бы не проблемы взаимодействия, команда .Net никогда бы не включила его в исходную спецификацию. Объектно-ориентированный способ решения большинства проблем, решаемых с помощью параметров ref, заключается в следующем:
Для нескольких возвращаемых значений
Для примитивов, которые изменяются в методе в результате вызова метода (метод имеет побочные эффекты на параметры примитива)
источник
IPAddress.TryParse(string, out IPAddress)
.if (int.TryParse("123", out var theInt) { /* use theInt */ }
у нас былоvar candidate = int.TrialParse("123"); if (candidate.Parsed) { /* do something with candidate.Value */ }
больше кода, но он намного больше соответствует дизайну языка C #.Вероятно, вы могли бы написать целое приложение C # и никогда не передавать какие-либо объекты / структуры по ссылке.
У меня был профессор, который сказал мне следующее:
Я согласен с его советом, и за пять с лишним лет, прошедших со школы, мне он никогда не требовался, кроме вызова Framework или Windows API.
источник
SetName(person, "John Doe")
, свойство name изменится, и это изменение будет отражено для вызывающей стороны.Поскольку receive_s - это массив, вы передаете указатель на этот массив. Функция манипулирует этими существующими данными на месте, не изменяя базовое местоположение или указатель. Ключевое слово ref означает, что вы передаете фактический указатель на местоположение и обновляете этот указатель во внешней функции, поэтому значение во внешней функции изменится.
Например, байтовый массив - это указатель на одну и ту же память до и после того, как память была только что обновлена.
Ссылка на конечную точку фактически обновляет указатель на конечную точку во внешней функции на новый экземпляр, созданный внутри функции.
источник
Думайте о ссылке как о том, что вы передаете указатель по ссылке. Отсутствие ссылки означает, что вы передаете указатель по значению.
А еще лучше проигнорируйте то, что я только что сказал (это, вероятно, вводит в заблуждение, особенно в отношении типов значений), и прочтите эту страницу MSDN .
источник
я понимаю, что все объекты, производные от класса Object, передаются как указатели, тогда как обычные типы (int, struct) не передаются как указатели и требуют ref. Я не уверен насчет строки (является ли она производным от класса Object?)
источник
Хотя я согласен с ответом Джона Скита в целом и некоторыми другими ответами, есть вариант использования для использования
ref
, а именно для усиления оптимизации производительности. Во время профилирования производительности было замечено, что установка возвращаемого значения метода имеет незначительные последствия для производительности, тогда как использованиеref
в качестве аргумента, посредством которого возвращаемое значение подставляется в этот параметр, приводит к устранению этого небольшого узкого места.Это действительно полезно только тогда, когда усилия по оптимизации доводятся до крайних уровней, жертвуя удобочитаемостью и, возможно, тестируемостью и ремонтопригодностью для экономии миллисекунд или, возможно, доли миллисекунд.
источник
Сначала правило нулевого уровня, примитивы передаются по значению (стек), а непримитивные по ссылке (куча) в контексте задействованных ТИПОВ.
Участвующие параметры по умолчанию передаются по значению. Хороший пост, в котором все подробно объясняется. http://yoda.arachsys.com/csharp/parameters.html
Мы можем сказать (с предупреждением), что непримитивные типы - это не что иное, как указатели. И когда мы передаем их по ссылке, мы можем сказать, что передаем двойной указатель.
источник