Невозможно использовать ref и out для первого параметра ("this") в методах расширения?
Почему запрещается вызывать 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;
}
Но почему?
Ответы
Ответ 1
Вы должны явно указать ref
и out
. Как вы это сделаете с помощью метода расширения? Более того, вы действительно хотите?
TestClass x = new TestClass();
(ref x).ChangeWithExtensionMethod(otherTestClass);
// And now x has changed?
Или вы не хотите указывать часть ref
только для первого параметра в методах расширения?
Это просто звучит странно для меня, если честно, и рецепт для нечитаемого (или, по крайней мере, трудно предсказанного) кода.
Ответ 2
Я согласен с ответами от Jon Skeet et al. о том, как разрешить методы "ref this" расширения могут сделать код более неясным. Но если вы посмотрите на некоторые пространства имен в .Net Framework, для метода, вызываемого в структуре, это является обычным.
Возьмем, к примеру, структуры System.Drawing(Point, Rectangle и т.д.). Каждый из них имеет методы (например, Offset, Inflate и т.д.), Которые сами мутируют структуру. Я не говорю, что это хорошая идея, на самом деле мне лично очень неприятно, что Offset, Inflate и т.д. Мутируют сами структуры, вместо того, чтобы возвращать новые, и я знаю, что некоторые из вас выступают против идеи изменчивых структур в вообще.
Я сомневаюсь, что есть случаи, когда вызов метода ссылочного типа изменяет ссылку (если только она не имеет класс String
, где я могу себе представить, что может быть какая-то магия компилятора для переключения ссылок на интернирование и т.д.), Поэтому имеет смысл запретить использование этого ссылки для ссылочных типов, поскольку изменение ссылки будет полностью нестандартным побочным эффектом вызова метода.
Но в отношении структур, позволяющих "этот ref" не будет значительно уменьшать читаемость кода больше, чем Rectangle.Inflate и т.д., и это будет единственным средством "имитировать" такое поведение с помощью функции расширения.
Как примечание, вот один пример, где "этот ref" может быть полезен, и IMHO все еще читаем:
void SwapWith<T>(this ref T x, ref T y) {
T tmp = x; x = y; y = tmp;
}
Ответ 3
Я согласен, что это полезно для struct
Поэтому я хочу предложить это для создания метода расширения для struct. это ключевое слово должно всегда передавать struct по ссылке
класс всегда передается по ссылке. И всякий раз, когда мы создаем метод расширения, мы хотим, чтобы он вел себя как настоящий метод. Таким образом, реальный метод класса и структуры может изменить его значение. Метод расширения также должен иметь возможность
Ответ 4
В С# 7.2 вы можете использовать методы расширения ref
Ответ 5
Это означало бы, что вызов myObject.ChangeWithExtentionMethod(otherObject)
действительно имел бы потенциал для изменения значения myObject
. IMO, который не будет делать для очень читаемого кода, когда вы можете вместо этого добиться желаемого эффекта, используя обычный метод без расширения с помощью ссылки.
EDIT: Моя точка зрения, вызов метода должен требовать от вас использовать ключевое слово ref в любое время, когда вы передаете что-то по ссылке. Использование ref с использованием метода расширения 'this' нарушит это поведение.
Ответ 6
не совсем верно, вы можете использовать ref в методах расширения только в С# 7.2, если это структура. https://github.com/dotnet/csharplang/issues/186