无法在扩展方法中使用 ref 和 out 作为第一个(“this”)参数?

发布于 2024-08-28 10:46:36 字数 389 浏览 10 评论 0原文

为什么禁止使用 ref 修饰符调用扩展方法

这个是可能的:

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

而这个则不行:

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

但是为什么呢?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不即不离 2024-09-04 10:46:36

我知道这是一个老问题。但事情已经改变了。万一有人正在寻找这个。

从 C# 7.2 开始,您可以将 ref 修饰符添加到第一个
扩展方法的参数。添加 ref 修饰符意味着
第一个参数通过引用传递。这使您能够编写
更改正在扩展的结构的状态的扩展方法。

仅允许值类型 (struct),而不允许引用类型(classinterfacerecord) 。

来源:Microsoft Docs,“扩展方法(C# 编程指南)- 扩展预定义类型”

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();
    }
}

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();
    }
}
红颜悴 2024-09-04 10:46:36

您必须显式指定 refout。您将如何使用扩展方法来做到这一点?此外,您真的想要吗?

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

或者您是否希望不必指定 ref 部分,而只为扩展方法中的第一个参数指定?

老实说,这对我来说听起来很奇怪,并且是不可读(或至少难以预测)代码的秘诀。

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.

天赋异禀 2024-09-04 10:46:36

我同意 Jon Skeet 等人的答案。关于允许“ref this”扩展方法如何使代码更加晦涩。但是,如果您查看 .Net Framework 中的某些命名空间,就会发现在结构上调用方法来更改它是很常见的。

以 System.Drawing 结构(点、矩形等)为例。其中每一个都有改变结构本身的方法(例如 Offset、Inflate 等)。我并不是说这是一个好主意,事实上,我个人觉得 Offset、Inflate 等改变结构本身而不是返回新结构非常烦人,而且我知道你们中的一些人反对可变结构的想法一般的。

我怀疑在任何情况下调用引用类型的方法都会更改引用(除非它是使用 String 类,我可以想象可能存在一些编译器魔术来切换引用以执行实习, ETC)。因此,防止“this ref”与引用类型一起使用是有意义的,因为更改引用将是调用方法的完全非标准的副作用。

但就结构而言,允许“this ref”不会比 Rectangle.Inflate 等显着降低代码可读性,并且它将提供使用扩展函数“模拟”此类行为的唯一方法。

作为旁注,这里有一个示例,其中“this ref”可能有用,并且恕我直言仍然可读:

void SwapWith<T>(this ref T x, ref T y) {
   T tmp = x; x = y; y = tmp;
}

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;
}
梦在夏天 2024-09-04 10:46:36

我同意它对 struct 很有用,

所以我想建议为 struct 制作扩展方法。 this 关键字应该始终通过引用传递结构,

无论如何,类总是通过引用传递。每当我们创建扩展方法时,我们都希望它的行为像真正的方法一样。所以类和结构的真实方法可以修改它的值。扩展方法应该也可以

I agree that it useful for struct

So I want to propose that for making extension method for struct. this keyword should always pass struct by reference

class always pass by reference anyway. And whenever we create extension method we want it to behave like a real method. So real method of class and struct can modified its value. Extension method should be able to too

眼眸里的快感 2024-09-04 10:46:36

这意味着调用 myObject.ChangeWithExtentionMethod(otherObject) 实际上有可能更改 myObject 的值。 IMO,当您可以通过使用带有 ref 的常规非扩展方法来实现所需的效果时,这不会产生非常可读的代码。

编辑:我的观点是,方法调用应该要求您在通过引用传递某些内容时使用 ref 关键字。将 ref 与扩展方法的“this”参数一起使用会违反该行为。

This would mean that calling myObject.ChangeWithExtentionMethod(otherObject) would actually have the potential to change myObject's value. IMO, that wouldn't make for very readable code when you can instead achieve the desired effect by using a regular non-extension method with a ref.

EDIT: My point is, the method call should require you to use the ref keyword any time that you're passing something by reference. Using ref with an extension method's 'this' parameter would violate that behavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文