Невозможно использовать ref и out для первого ("this") параметра в методах расширения? - PullRequest
26 голосов
/ 12 апреля 2010

Почему запрещено звонить Extension Method с ref модификатором?

Это возможно:

public static void Change(ref TestClass testClass, TestClass testClass2)
{
    testClass = testClass2;
}

А этот нет:

public static void ChangeWithExtensionMethod(this ref TestClass testClass, TestClass testClass2)
{
    testClass = testClass2;
}

Но почему?

Ответы [ 5 ]

21 голосов
/ 12 апреля 2010

Вы должны указать ref и out явно. Как бы вы сделали это с методом расширения ? Кроме того, вы бы действительно хотели бы до?

TestClass x = new TestClass();
(ref x).ChangeWithExtensionMethod(otherTestClass);
// And now x has changed?

Или вы не хотите указывать часть ref, только для первого параметра в методах расширения?

Это звучит странно, если честно, и рецепт нечитаемого (или, по крайней мере, трудно предсказуемого) кода.

9 голосов
/ 05 декабря 2012

Я согласен с ответами Джона Скита и соавт. о том, как использование методов расширения «ref this» может сделать код более неясным. Но если вы посмотрите на некоторые пространства имен в .Net Framework, то метод, вызываемый в структуре, обычно изменяет ее.

Возьмем, например, структуры System.Drawing (точка, прямоугольник и т. Д.). У каждого из них есть методы (например, Offset, Inflate и т. Д.), Которые изменяют саму структуру. Я не говорю, что это хорошая идея, на самом деле меня лично очень раздражает, что Offset, Inflate и т. Д. Изменяют сами структуры вместо того, чтобы возвращать новые, и я знаю, что некоторые из вас выступают против идеи изменяемых структур в общий.

Я сомневаюсь, что есть случаи, когда вызов метода ссылочного типа изменит ссылку (если только это не класс String, где я могу представить, что может быть какая-то магия компилятора для переключения ссылок для выполнения интернирования и т. Д.) , Поэтому имеет смысл не использовать «этот ref» с ссылочными типами, потому что изменение ссылки было бы совершенно нестандартным побочным эффектом вызова метода.

Но что касается структур, то использование «этого ref» не будет значительно снижать читаемость кода больше, чем Rectangle.Inflate и т. Д., И это обеспечит единственное средство для «моделирования» такого рода поведения с помощью функции расширения.

Так же, как примечание, вот один пример, где «этот ref» может быть полезным, и ИМХО по-прежнему читаемым:

void SwapWith<T>(this ref T x, ref T y) {
   T tmp = x; x = y; y = tmp;
}
3 голосов
/ 12 мая 2015

Я согласен, что это полезно для структуры

Итак, я хочу предложить это для создания метода расширения для структуры. это ключевое слово всегда должно передавать struct по ссылке

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

2 голосов
/ 21 ноября 2018

В C # 7.2 вы можете использовать методы расширения ref

1 голос
/ 12 апреля 2010

Это будет означать, что вызов myObject.ChangeWithExtentionMethod(otherObject) действительно может изменить значение myObject. IMO, это не сделало бы очень читабельный код, когда вы могли бы вместо этого достичь желаемого эффекта, используя обычный метод без расширения с ref.

РЕДАКТИРОВАТЬ: Моя точка зрения заключается в том, что вызов метода должен потребовать от вас использовать ключевое слово ref каждый раз, когда вы передаете что-то по ссылке. Использование ref с параметром this метода расширения нарушило бы это поведение.

...