Пройдя по ссылке?
Я все еще путаюсь прохождение по ссылке.
Если у меня есть объект Cache, к которому я хочу получить доступ/доступ к целому ряду объектов, и я его вставляю с помощью вставки конструктора. Я хочу, чтобы это повлияло на один созданный мной объект кеша. например.
public class Cache {
public void Remove(string fileToRemove) {
...
}
}
public class ObjectLoader {
private Cache _Cache;
public ObjectLoader(Cache cache) {
}
public RemoveFromCacheFIleThatHasBeenDeletedOrSimilarOperation(string filename) {
_Cache.Remove(fileName);
}
}
Должен ли я использовать ref при передаче кеша в конструктор ObjectLoader?
Ответы
Ответ 1
Нет, вам не нужно использовать ключевое слово ref в этой ситуации.
Кэш - это класс, он является ссылочным типом. Когда ссылка передается в метод, копия ссылки (а не самого объекта) помещается в ваш параметр. Обе ссылки внутри и снаружи метода указывают на один и тот же объект в куче, а изменение полей объекта с помощью одного будет отражено в другом.
Добавление ссылки ref к вызову метода в исходной ссылке. Это полезно в ситуации, когда вы переназначаете (т.е. Вызываете new
) местоположение, на которое ссылается ссылка внутри вызывающего метода.
Ответ 2
Используйте ключевое слово 'ref', когда вам нужно изменить то, на что указывает ссылка. Когда вы передаете ссылочный тип в метод, он передается по значению, но это значение является копией этой ссылки, которая передается методу. Это означает, что вы можете изменить общее состояние (т.е. Свойства/поля) упомянутого объекта, но если вы попытаетесь изменить то, что ориентиры указывают на вас, это повлияет только на копию.
Например, данный метод...
private void Foo( MyClass obj )
{
obj = new MyClass( );
obj.SomeProperty = true;
}
Мы можем передать аргумент, а затем посмотреть, было ли это затронуто:
MyClass test = new MyClass( );
test.SomeProperty = false;
Foo( test );
Console.WriteLine( test.SomeProperty ); // prints "False"
Теперь, если мы определили метод, используя ключевое слово 'ref'...
private void Foo( ref MyClass obj )
{
obj = new MyClass( );
obj.SomeProperty = true;
}
Выход будет "True", потому что фактическая ссылка была передана методу, а не копия. Мы изменили то, что эта ссылка указывает на функцию, и мы видим последствия этих изменений.
Вы просто создаете новый указатель на объект в куче, когда опускаете ключевое слово 'ref'. Если вы измените один указатель, вы не измените другого.
...
Итак, чтобы ответить на ваш вопрос; нет, вам не нужно использовать ключевое слово 'ref', чтобы изменить состояние вашего одного объекта Cache, когда оно передается методу.
Ответ 3
Я думаю, вам интересно, сколько копий объекта Cache
будет создано. Вы хотите, чтобы один экземпляр был доступен нескольким клиентским объектам. Ну, там очень простое правило, которое вы можете запомнить на С#, когда захотите узнать, сколько отдельных копий вашего объекта будет создано.
Если тип объекта объявлен с ключевое слово class
, то есть только один способ сделать новый экземпляр it: с ключевым словом new
.
Есть незначительные исключения из этого: вы можете вызвать методы BCL, которые создают объекты, но дело в том, что оно явное. Вы должны специально просить об этом. Язык не будет автоматически создавать копии объектов class
.
Итак, в вашем примере у вас есть class
, называемый Cache
, и поэтому вы наверняка знаете, что можете обойти переменные типа Cache
столько, сколько хотите, и никаких дополнительных копий Cache
будут созданы. Все переменные, у которых есть назначенный им объект, будут "указывать" на один и тот же исходный объект. Это связано с тем, что переменная Cache
не хранит сам объект, а только местоположение объекта Cache
в памяти.
Сравните это с тем, что произойдет, если вы объявите тип struct
вместо class
. Теперь, когда вы объявляете переменную этого типа, сама переменная должна быть достаточно большой, чтобы хранить все данные, объявленные в struct
. Каждая переменная является отдельной копией. Каждый параметр является отдельной копией.
Вы можете переопределить это, добавив ключевое слово ref
, но это довольно необычное ключевое слово в большинстве программ. Ключевое слово out
является более распространенным, и лучше всего рассматривать его как способ предоставить метод более одного возвращаемого значения.
Какое влияние оказывает ref
на переменную, если она имеет тип class
? В вашем примере:
public ObjectLoader(Cache cache) {
// do stuff with cache (store it?)
}
Я мог бы построить два загрузчика объектов следующим образом:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(c),
ObjectLoader b = new ObjectLoader(c);
Сколько объектов мы только что создали? Просто считайте ключевые слова new
. Теперь предположим, что мы добавили ключевое слово ref
:
public ObjectLoader(ref Cache cache) {
_cache = cache; // store
// do something very odd!
cache = new Cache();
}
Скрытый внутри этого конструктора, я создал другой кеш и сохранил его в параметре, который был передан. Поскольку это параметр ref
, я затронул переменную вызывающего абонента! Итак, в вызывающем коде:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(ref c),
ObjectLoader b = new ObjectLoader(ref c);
Теперь у нас есть пять вариантов использования new
: три в приведенном выше фрагменте, плюс два обращения к модифицированному конструктору ObjectLoader
. Каждый раз, когда вызывается конструктор ObjectLoader
, мы передаем его c
. Мы должны поставить ключевое слово ref
, что очень хорошо, потому что он позволяет человеку, читающему код, знать, что что-то странное происходит. Переменная c
указывает на другой Cache
после возврата конструктора ObjectLoader
. Таким образом, b
ObjectLoader
заканчивает сохранение указателя на другой Cache
до a
!
Излишне говорить, что это был бы довольно грязный шаблон для кода. Было бы еще хуже, если бы нам не пришлось поставить ключевое слово ref
на вызывающий сайт!
Ответ 4
Объекты автоматически передаются по ссылке, даже если вы объявляете их переданными по значению в аргументах функций в платформе .NET.
Это связано с тем, что сам объект является ссылочным типом, поэтому вы можете изменять элементы объекта, даже если вы не можете заменить сам объект.
См
http://msdn.microsoft.com/en-us/library/aa903253(VS.71).aspx