Передайте, ref
если вы хотите изменить объект:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
После вызова DoSomething t
не ссылается на оригинал new TestRef
, но ссылается на совершенно другой объект.
Это также может быть полезно, если вы хотите изменить значение неизменяемого объекта, например, a string
. Вы не можете изменить значение, string
если оно было создано. Но, используя ref
, вы можете создать функцию, которая изменяет строку на другую, которая имеет другое значение.
Изменить: как уже упоминали другие люди. Это не очень хорошая идея, ref
если она не нужна. Использование ref
дает методу свободу изменять аргумент для чего-то другого, вызывающие методы должны быть закодированы, чтобы гарантировать, что они обрабатывают эту возможность.
Кроме того, когда тип параметра является объектом, переменные объекта всегда действуют как ссылки на объект. Это означает, что при использовании ref
ключевого слова вы получаете ссылку на ссылку. Это позволяет вам делать вещи, как описано в приведенном выше примере. Но когда тип параметра является примитивным значением (например,int
), тогда, если этот параметр назначен внутри метода, значение переданного аргумента будет изменено после возврата метода:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
ref
на сайте вызовов ... где еще вы хотели бы, чтобы его различали? Семантика также достаточно ясна, но должна быть выражена осторожно (а не «объекты передаются по ссылке», что является обычным упрощением).В .NET, когда вы передаете какой-либо параметр методу, создается копия. В типах значений означает, что любое изменение, внесенное вами в значение, находится в области действия метода и теряется при выходе из метода.
При передаче типа ссылки также создается копия, но это копия ссылки, то есть теперь у вас есть две ссылки в памяти на один и тот же объект. Таким образом, если вы используете ссылку для изменения объекта, он будет изменен. Но если вы измените саму ссылку - мы должны помнить, что это копия - тогда любые изменения также будут потеряны при выходе из метода.
Как уже говорили люди, назначение является модификацией ссылки, поэтому теряется:
Методы выше не изменяют исходный объект.
Небольшая модификация вашего примера
источник
Поскольку TestRef является классом (который является ссылочным объектом), вы можете изменить содержимое внутри t, не передавая его как ссылку. Однако, если вы передадите t как ссылку, TestRef может изменить то, на что ссылается исходный t. то есть, чтобы он указывал на другой объект.
источник
С помощью
ref
вы можете написать:И т будет изменен после завершения метода.
источник
Думайте о переменных (например
foo
) ссылочных типов (напримерList<T>
) как об удерживающих идентификаторах объекта формы "Объект # 24601". Предположим, операторfoo = new List<int> {1,5,7,9};
причиныfoo
держать «Объект # 24601» (список с четырьмя пунктами). Затем вызывающийfoo.Length
запросит у Объекта # 24601 его длину, и он ответит 4, поэтомуfoo.Length
будет равен 4.Если
foo
метод передается без использованияref
, этот метод может внести изменения в объект № 24601. Как следствие таких изменений, ониfoo.Length
могут больше не равняться 4. Однако сам метод не сможет изменитьсяfoo
, что будет продолжать содержать «Объект № 24601».Передача
foo
в качествеref
параметра позволит вызываемому методу вносить изменения не только в объект № 24601, но и вfoo
самого себя. Метод может создать новый объект # 8675309 и сохранить ссылку на него вfoo
. Если это так,foo
он больше не будет содержать «Объект № 24601», а вместо «Объект № 8675309».На практике переменные ссылочного типа не содержат строки вида «Объект # 8675309»; они даже не содержат ничего, что могло бы значимо преобразоваться в число. Даже если каждая переменная ссылочного типа будет содержать некоторую битовую комбинацию, не существует фиксированной связи между битовыми комбинациями, хранящимися в таких переменных, и объектами, которые они идентифицируют. Нет никакого способа, которым код мог бы извлечь информацию из объекта или ссылку на него, а затем определить, идентифицировала ли другая ссылка тот же объект, если только код не содержал или знал ссылку, идентифицирующую исходный объект.
источник
Это похоже на передачу указателя на указатель в C. В .NET это позволит вам изменить то, на что ссылается оригинальный T, лично, хотя я думаю, что если вы делаете это в .NET, у вас, вероятно, есть проблема с дизайном!
источник
Используя
ref
ключевое слово со ссылочными типами, вы фактически передаете ссылку на ссылку. Во многих отношениях это то же самое, что и использованиеout
ключевого слова, но с небольшим отличием в том, что нет никакой гарантии, что метод фактически назначит что-либо параметруref
'ed.источник
ref
подражает (или ведет себя) как глобальная область только для двух областей:источник
Однако если вы передаете значение, все иначе. Вы можете принудительно передать значение по ссылке. Это позволяет вам передавать целое число, например, в метод, и заставлять метод изменять целое число от вашего имени.
источник
Ref обозначает, может ли функция взять в руки сам объект или только его значение.
Передача по ссылке не связана с языком; это стратегия привязки параметров рядом с передачей по значению, передачей по имени, передачей по необходимости и т. д ...
Заметка: имя класса
TestRef
- ужасно плохой выбор в этом контексте;).источник