Есть ли разница между методом void, который принимает тип ref и манипулирует им, и методом, который возвращает ref для того же объекта? - PullRequest
2 голосов
/ 25 января 2012

Есть ли большая разница между этими двумя, если манипуляции идентичны?В примере 1 передается ссылка на объект, и объектом манипулируют.В примере 2 передается ссылка на объект, объектом манипулируют, а затем ... возвращается та же ссылка?

static void Foo(SomeReferenceType t)
{
    //Do something with t
}

static SomeReferenceType Foo(SomeReferenceType t)
{
    //Do same thing with t
    return t;
}

Bar bar = new Bar();

//Does this
Foo(bar);
//Do the same thing as this
bar = Foo(bar);

Ответы [ 5 ]

3 голосов
/ 25 января 2012

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

В первом случае потребитель передает переменную и говорит: «Дорогой метод, пожалуйста, возьми эту переменную и делай с ней все, что хочешь, включая, возможно, указание ее на новый адрес памяти».Таким образом, разработчик знает, что переданным состоянием можно манипулировать.

Кстати, я думаю, вы должны прочитать это: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx

Когда я беру интервью у потенциальных разработчиков, я спрашиваю многовопросов о передаче ссылочных и значений типов по ссылке и по значению.Я брал интервью у разработчиков на должности очень высокого уровня, которые не понимают этого, но я думаю, что это фундаментально для разработки на C #.

1 голос
/ 25 января 2012

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

Если единственным намерением метода являетсячтобы изменить объект, он должен быть определен в классе SomeReferenceType, поэтому метод и данные, которые он изменяет, инкапсулированы вместе:

class SomeReferenceType()
{
  public void Foo()
  {
      // mutate instance here
  }
}

SomeReferenceType a = new SomeReferenceType();
a.Foo();
0 голосов
/ 25 января 2012

В этом конкретном случае, да, он делает то же самое.

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

0 голосов
/ 25 января 2012

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

0 голосов
/ 25 января 2012

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

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

SomeReferenceType result = obj.Foo()
                              .Bar()
                              .Baz()
...