Пройдя по ссылке?

Я все еще путаюсь прохождение по ссылке.

Если у меня есть объект 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