简体   繁体   English

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

[英]Impossible to use ref and out for first ("this") parameter in Extension methods?

Why is it forbidden to call Extension Method with ref modifier?为什么禁止使用ref修饰符调用Extension Method

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.您必须明确指定refout 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?或者您不想只为扩展方法中的第一个参数指定ref部分?

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.我同意 Jon Skeet 等人的回答。 about how allowing "ref this" extension methods could make the code more obscure.关于允许“ref this”扩展方法如何使代码更加晦涩。 But if you look at some namespaces in the .Net Framework, it is common for a method invoked on a struct to alter it.但是,如果您查看 .Net Framework 中的某些命名空间,通常会在结构上调用方法来更改它。

Take for example the System.Drawing structs (Point, Rectangle, etc).以 System.Drawing 结构(点、矩形等)为例。 Each of these has methods (eg Offset, Inflate, etc) that mutate the struct itself.每一个都有改变结构本身的方法(例如 Offset、Inflate 等)。 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.我并不是说这是一个好主意,事实上我个人觉得 Offset、Inflate 等改变结构本身而不是返回新结构非常烦人,而且我知道你们中的一些人反对可变结构的想法一般的。

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

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.但是对于结构,允许“this ref”不会比 Rectangle.Inflate 等更显着降低代码可读性,并且它将提供使用扩展函数“模拟”这种行为的唯一方法。

Just as a side-note, here is one example where "this ref" might be useful, and IMHO still readable:作为旁注,这里有一个例子,其中“this ref”可能有用,恕我直言仍然可读:

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

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.从 C# 7.2 开始,您可以将 ref 修饰符添加到扩展方法的第一个参数。 Adding the ref modifier means the first argument is passed by reference.添加 ref 修饰符意味着第一个参数通过引用传递。 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 ).这仅适用于值类型( struct ),而不适用于引用类型( classinterfacerecord )。

Source: Microsoft Docs, "Extension Methods (C# Programming Guide) — Extending Predefined Types" .来源: 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 agree that it useful for struct我同意它对结构有用

So I want to propose that for making extension method for struct.所以我想提出这个来制作struct的扩展方法。 this keyword should always pass struct by reference this 关键字应始终通过引用传递结构

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扩展方法应该也可以

This would mean that calling myObject.ChangeWithExtentionMethod(otherObject) would actually have the potential to change myObject 's value.这意味着调用myObject.ChangeWithExtentionMethod(otherObject)实际上有可能改变myObject的值。 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. IMO,当您可以通过使用带有 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.编辑:我的观点是,方法调用应该要求您在通过引用传递某些内容时使用 ref 关键字。 Using ref with an extension method's 'this' parameter would violate that behavior.将 ref 与扩展方法的“this”参数一起使用会违反该行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM