在谈论 C# 7.2 ref 扩展方法时,"this ref" 和 "ref this" 有什么区别?



请考虑以下扩展方法:

public static void Toggle(this ref bool @bool) => @bool = !@bool;
public static void Toggle2(ref this bool @bool) => @bool = !@bool;

这些只是切换一个 ref 布尔变量值。测试:

class Foo
{
private bool _flag;
public void DoWork()
{
_flag.Toggle();
Console.WriteLine(_flag);
_flag.Toggle2();
Console.WriteLine(_flag);
}
}

我们得到:

True
False

问题:选择一种语法或另一种语法有什么隐藏的区别吗?

不,它们是完全相同的,就像(现在(您可以使用$@@$编写插值逐字字符串文字一样。

没有区别。这些称为修饰符,它们在规范中的顺序未定义

可以在此处阅读有关 C# 语言规范中方法参数的部分:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#method-parameters

它列出了不同的选项并定义了它们如何交互和混合,但没有说明您必须使用的顺序。

尽管根据语言规范,它们是完全相同的。我发现了一个必须对编译器做更多事情的差异,这可能是编译器的错误。重现这一点的设置是Visual Studio 2019。该错误可能存在于其他编译器版本中,我真的没有对此进行更多研究。

如果您的语言水平为 7.2 或更高,则两种语法的工作方式相同。但是,如果您的项目使用语言级别 7.0 或 7.1,则将编译以下内容:

struct S {}
static class Extensions
{
static void M(this ref S s) {}
}

但是如果我们像这里这样更改修饰符的顺序:

static class Extensions
{
static void M(ref this S s) {}
}

您将收到以下编译器错误消息:

错误 CS8107:功能 "ref 扩展方法" 在 C# 7.0 中不可用。请使用语言版本 7.2 或更高版本。

奇怪的是,尽管static void M(this ref S s)编译,但没有办法将该方法用作S的扩展方法:

s.M() //error CS8107 here

但是您可以使用传统的静态语法调用该方法:

Extensions.M(ref s)

因此,尽管在语言规范方面没有区别,但对于那些使用 Roslyn 编译器的人来说,最好使用this ref而不是ref this因为只要存在错误,它就会向后兼容 7.0 和 7.1 IMO

我在这里报告了缺乏有关结构的引用扩展方法的信息,其他一些人向 Roslyn 报告了这个问题。

我没有将这个答案标记为答案,因为我认为@Jon Skeet和@Joel Coehoorn的答案在语言方面更准确。但我认为无论如何这都是有用的信息

最新更新