Когда использовать ref и когда это не нужно в C #

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

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 ?

Я также программист AC, поэтому у меня проблема с получением указателей из головы.

Изменить: похоже, что объекты в C # являются указателями на объект под капотом. Поэтому, когда вы передаете объект функции, вы можете изменить содержимое объекта через указатель, и единственное, что передается функции, – это указатель на объект, поэтому сам объект не копируется. Вы используете ref или out, если хотите, чтобы вы могли отключить или создать новый объект в функции, которая похожа на двойной указатель.

    Краткий ответ: прочитайте мою статью о передаче аргументов .

    Длинный ответ: когда параметр ссылочного типа передается по значению, передается только ссылка, а не копия объекта. Это похоже на передачу указателя (по значению) в C или C ++. Вызов вызывающего объекта не будет изменен на изменение значения самого параметра, но изменения объекта, на который указывает эта ссылка, будут видны.

    Когда параметр (любого вида) передается по ссылке, это означает, что любые изменения в параметре видны вызывающей стороне – изменения в параметре являются изменениями в переменной.

    В статье объясняется все это более подробно, конечно 🙂

    Полезный ответ: вам почти никогда не нужно использовать ref / out . Это в основном способ получить другое возвращаемое значение и обычно следует избегать именно потому, что это означает, что метод, вероятно, пытается сделать слишком много. Это не всегда так ( TryParse т. Д. Являются каноническими примерами разумного использования out ), но использование ref / out должно быть относительной редкостью.

    Подумайте о параметре non-ref как указателе и параметре ref как двойной указатель. Это помогло мне больше всего.

    Вы почти никогда не должны передавать значения по ссылке. Я подозреваю, что если это не касается проблем взаимодействия, команда .Net никогда бы не включила его в исходную спецификацию. Способ OO для решения большинства проблем, которые решают параметры, заключается в следующем:

    Для нескольких значений возврата

    • Создание структур, которые представляют собой множественные возвращаемые значения

    Для примитивов, которые изменяются в методе в результате вызова метода (метод имеет побочные эффекты на примитивные параметры)

    • Реализовать метод в объекте как метод экземпляра и манипулировать состоянием объекта (а не параметрами) как частью вызова метода
    • Используйте решение с множественным возвратным значением и объедините возвращаемые значения в ваше состояние
    • Создайте объект, который содержит состояние, которое можно манипулировать с помощью метода, и передать этот объект в качестве параметра, а не сами примитивы.

    Вероятно, вы могли бы написать целое приложение C # и никогда не передавать никакие объекты / структуры по ссылке ref.

    У меня был профессор, который сказал мне это:

    Единственное место, где вы будете использовать refs, – это то, где вы:

    1. Хотите передать большой объект (т. Е. Объекты / struct имеют объекты / структуры внутри него на несколько уровней), и копирование было бы дорогостоящим и
    2. Вы вызываете Framework, Windows API или другой API, который требует его.

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

    Я согласен с его советом, и за пять с лишним лет после школы мне никогда не приходилось заходить за frameworks Framework или Windows API.

    Поскольку received_s – это массив, вы передаете указатель на этот массив. Функция управляет этими существующими данными на месте, не изменяя основное местоположение или указатель. Ключевое слово ref означает, что вы передаете фактический указатель на местоположение и обновляете этот указатель во внешней функции, поэтому значение во внешней функции изменится.

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

    Ссылка на конечную точку фактически обновляет указатель на конечную точку во внешней функции на новый экземпляр, созданный внутри функции.

    Подумайте о том, что ссылка означает, что вы передаете указатель по ссылке. Не использовать ref означает, что вы передаете указатель по значению.

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

    я понимаю, что все объекты, полученные из classа Object, передаются как указатели, тогда как обычные типы (int, struct) не передаются как указатели и требуют ref. Я не уверен в строке (это в конечном итоге происходит из classа Object?)

    В то время как я согласен с ответом Джона Скита в целом и некоторыми другими ответами, существует прецедент для использования ref , и это связано с ужесточением оптимизации производительности. Во время профилирования производительности наблюдалось, что установка возвращаемого значения метода имеет небольшие последствия для производительности, тогда как использование ref в качестве аргумента, при котором возвращаемое значение заполняется этим параметром, приводит к удалению этого небольшого узкого места.

    Это действительно полезно, когда усилия по оптимизации принимаются на экстремальных уровнях, жертвуя удобочитаемостью и, возможно, тестируемостью и ремонтопригодностью для сохранения миллисекунд или, возможно, сплит-миллисекунд.

    Первое правило нуля: примитивы передаются по значению (стек) и не примитивному по ссылке (куча) в контексте задействованных ТИПОВ.

    Приведенные параметры передаются по умолчанию по умолчанию. Хороший пост, который объясняет вещи в деталях. http://yoda.arachsys.com/csharp/parameters.html

     Student myStudent = new Student {Name="A",RollNo=1}; ChangeName(myStudent); static void ChangeName(Student s1) { s1.Name = "Z"; // myStudent.Name will also change from A to Z // {AS s1 and myStudent both refers to same Heap(Memory) //Student being the non-Primitive type } ChangeNameVersion2(ref myStudent); static void ChangeNameVersion2(ref Student s1) { s1.Name = "Z"; // Not any difference {same as **ChangeName**} } static void ChangeNameVersion3(ref Student s1) { s1 = new Student{Name="Champ"}; // reference(myStudent) will also point toward this new Object having new memory // previous mystudent memory will be released as it is not pointed by any object } 

    Мы можем сказать (с предупреждением). Непримитивные типы – это не что иное, как указатели. И когда мы передаем их по ref, мы можем сказать, что мы передаем Double Pointer

    Давайте будем гением компьютера.