Impossible to use ref and out for first ("this") parameter in Extension methods?
Why is it forbidden to call Extension Method
with ref
modifier?
This one is possible:
public static void Change(ref TestClass testClass, TestClass testClass2)
{
testClass = testClass2;
}
And this one not:
public static void ChangeWithExtensionMethod(this ref TestClass testClass, TestClass testClass2)
{
testClass = testClass2;
}
But why?
You have to specify ref
and out
explicitly. How would you do this with an extension method? Moreover, would you really want to?
TestClass x = new TestClass();
(ref x).ChangeWithExtensionMethod(otherTestClass);
// And now x has changed?
Or would you want to not have to specify the ref
part, just for the first parameter in extension methods?
It just sounds weird to me, to be honest, and a recipe for unreadable (or at least hard-to-predict) code.
I agree with the answers from Jon Skeet et al. about how allowing "ref this" extension methods could make the code more obscure. But if you look at some namespaces in the .Net Framework, it is common for a method invoked on a struct to alter it.
Take for example the System.Drawing structs (Point, Rectangle, etc). Each of these has methods (e.g. Offset, Inflate, etc) that mutate the struct itself. I'm not saying this is a good idea, in fact I personally find it very annoying that Offset, Inflate, etc mutate the structs themselves instead of returning new ones, and I know some of you are opposed to the idea of mutable structs in general.
I doubt there are any cases where invoking a method of a reference type will change the reference (unless it's with the String
class, where I can imagine there might be some compiler magic to switch references to perform interning, etc). So it makes sense to prevent "this ref" from being used with reference types, because changing a reference would be a completely non-standard side-effect of calling a method.
But in regards to structs, allowing "this ref" would not significantly decrease code readability any more than Rectangle.Inflate, etc, and it would provide the only means to "simulate" that kind of behavior with an extension function.
Just as a side-note, here is one example where "this ref" might be useful, and IMHO still readable:
void SwapWith<T>(this ref T x, ref T y) {
T tmp = x; x = y; y = tmp;
}
In C# 7.2 you can use ref extension methods for structs
See https://github.com/dotnet/csharplang/issues/186 and https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md
I know it's an old questions. But things have changed. In case anybody is looking for this.
Beginning with C# 7.2, you can add the ref modifier to the first argument of an extension method. Adding the ref modifier means the first argument is passed by reference. This enables you to write extension methods that change the state of the struct being extended.
This is allowed only for value types (struct
), and not reference types (class
, interface
, record
).
Source: Microsoft Docs, "Extension Methods (C# Programming Guide) — Extending Predefined Types".
public struct MyProperties
{
public string MyValue { get; set; }
}
public static class MyExtensions
{
public static void ChangeMyValue(this ref MyProperties myProperties)
{
myProperties.MyValue = "hello from MyExtensions";
}
}
public class MyClass
{
public MyClass()
{
MyProperties myProperties = new MyProperties();
myProperties.MyValue = "hello world";
myProperties.ChangeMyValue();
}
}