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

时间:2019-08-16 21:03:26

标签: c# extension-methods ref c#-7.2

请考虑以下扩展方法:

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

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

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

您可以在C# Language Specification中阅读有关方法参数的部分:

  

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

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

答案 2 :(得分:0)

尽管根据语言规范它们完全相同。我发现必须对编译器做更多的改变,这可能是编译器错误。重现此设置是在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: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就是这个错误了

我报告here缺少有关struct的ref扩展方法的信息,而另一些人则向Roslyn报告了该问题。

我没有将此答案标记为答案,因为我认为@Jon Skeet和@Joel Coehoorn的语言在语言方面更为准确。但是我仍然认为这是有用的信息