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

Posted

技术标签:

【中文标题】在谈论 C# 7.2 ref 扩展方法时,“this ref”和“ref this”有啥区别?【英文标题】:What is the difference between "this ref" and "ref this" when talking about C# 7.2 ref extension methods?在谈论 C# 7.2 ref 扩展方法时,“this ref”和“ref this”有什么区别? 【发布时间】:2019-12-23 03:50:03 【问题描述】:

考虑以下扩展方法:

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

还有一件事要问。声明静态异步方法时,是否有区别:public static async... vs public async static? 根据语言规范,它们完全相同,但根据 Roslyn =) @taquion 你能解释一下吗?似乎您可能在暗示某种经过充分讨论的争议或其他(尽管您的信息是一个需要分析的微小“信号”)。无论如何,您能为我这样的非 Roslyn 专家详细说明吗?【参考方案2】:

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

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

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

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

【讨论】:

根据语言规范,它们完全相同,但根据 Roslyn =)【参考方案3】:

尽管根据语言规范它们完全相同。我发现了一个差异,它必须对编译器做更多的事情,这可能是一个编译器错误。重现此问题的设置是使用 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那里海事组织

我向here 报告了缺少结构的引用扩展方法的信息,而其他一些人向Roslyn 报告了这个问题。

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

【讨论】:

"...最好使用this ref 而不是ref this"... 嗯,真的吗?仅基于阅读您信息中的优秀信息,我会倾向于相反的方式。对我来说,“[无法] [无法]将该方法用作扩展方法”似乎比“向后兼容 7.0 和 7.1”更严重。前者既是语言存在实体领域的错误和限制,编译器修订打嗝似乎是行政死水?也许因为 C# 如此稳定可靠,我只是假设每个人都将旧版本留在了死里......

以上是关于在谈论 C# 7.2 ref 扩展方法时,“this ref”和“ref this”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

ref readonly 的 C# 行为

由 ref 返回的值类型变量在哪里存在?堆栈还是堆?

具有 Ref Return Gets 的 C# 索引器也支持 Set

C# 中“in”参数的用途

C# 中的 in 参数和性能分析

C# 中的 Ref int 问题