简体   繁体   English

为什么不能在 C# 9 中定义顶级扩展方法?

[英]Why can't I define top-level extension methods in C# 9?

I had thought that using the Top-Level Statements feature in C# 9 essentially wraps your top-level code in the usual Program class and Main method.我曾认为使用 C# 9 中的顶级语句功能基本上将您的顶级代码包装在通常的Program class 和Main方法中。

A decompiled top-level program looks like this:一个反编译的顶层程序如下所示:

[CompilerGenerated]
internal static class $Program
{
    private static void $Main(string[] args)
    {
        // top-level code here
    }
}

You can define normal methods at the top-level.您可以在顶层定义普通方法。 They are compiled into the Program class, but outside of the Main method, where extension methods can also be defined.它们被编译到Program class 中,但在Main方法之外,也可以定义扩展方法。

Because the generated Program class is static and non-generic, I would expect to be able to define extension methods at the top level.因为生成的Program class 是 static 和非泛型,我希望能够在顶层定义扩展方法。 However, I get compiler error CS1106: Extension method must be defined in a non-generic static class但是,我得到编译器错误CS1106: Extension method must be defined in a non-generic static class

VS Code 编译器错误 CS1106:扩展方法必须在非泛型静态类中定义

Why is this?为什么是这样?

The C# Language Specification says: C# 语言规范说:

When the first parameter of a method includes the this modifier, that method is said to be an extension method .当方法的第一个参数包含this修饰符时,该方法称为扩展方法 Extension methods can only be declared in non-generic, non-nested static classes.扩展方法只能在非泛型、非嵌套 static 类中声明。

According to the language specification, extension methods must be declared in a static class.根据语言规范,扩展方法必须在 static class 中声明

It does not matter that top-level methods are implemented by placing them in a hidden static class.顶层方法通过将它们放置在隐藏的 static class 中来实现并不重要。 Top-level methods are (by definition) not declared in any class, and therefore cannot be extension methods according to the specification.顶级方法(根据定义)未在任何class 中声明,因此根据规范不能是扩展方法。

As with all language design questions, this is the way that it is because this is the way that the language design team designed the language.与所有语言设计问题一样,这就是它的方式,因为这是语言设计团队设计语言的方式。 Presumably the same concerns which prevent you from defining extension methods inside non-static classes also apply to top-level methods.可能阻止您在非静态类中定义扩展方法的相同问题也适用于顶级方法。

You can open a discussion in the csharplang repo or ask a question on Gitter if you want someone with more authority to possibly give more detail.您可以在csharplang 存储库中打开讨论,或者在 Gitter 上提问,如果您希望有更多权限的人可能提供更多详细信息。

The top-level statement feature is implemented the way you described it: your top level code is wrapped into the compiler generated class and Main method .顶级语句功能按照您描述的方式实现:您的顶级代码被包装到编译器生成的 classMain方法中。

Your extension cannot be declared inside this Main method, so your syntax is invalid.您的扩展不能在此Main方法中声明,因此您的语法无效。 An extension declaration is not a top-level statement.扩展声明不是顶级语句。

Using SharpLab we can see that, yes, the generated Program is static, and multiple methods declared in a top level context do get compiled correctly (example here ), something is missing when comparing to extension methods: The [Extension] attribute, as both the class and method need to be marked with this, official docs here .使用SharpLab我们可以看到,是的,生成的Program是 static,并且在顶级上下文中声明的多个方法确实可以正确编译(例如这里),与扩展方法相比时缺少一些东西: [Extension]属性,因为两者class 和方法需要用这个标记,官方文档在这里

This is the code generated by a top level Hello World (some things omited for brevity, full thing here )这是由顶级Hello World生成的代码(为简洁起见省略了一些内容, 此处为完整内容)

[assembly: Extension]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[CompilerGenerated]
internal static class <Program>$
{
    private static void <Main>$(string[] args)
    {
        Console.WriteLine("Hello World");
    }
}

Now here's the decompiled code for a class with an extension method:现在这里是带有扩展方法的 class 的反编译代码:

[Extension]
internal static class Foo
{
    [Extension]
    private static void WriteToConsole(string source)
    {
        Console.WriteLine(source);
    }
}

Seems like the compiler isn't recognizing that there are extension methods, and as such isn't compiling it correctly.似乎编译器没有识别出有扩展方法,因此没有正确编译它。 We also can't forcibly place the Extension attribute, as we then get an error saying that我们也不能强行放置Extension属性,因为我们会得到一个错误提示

error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'.错误 CS1112:不要使用“System.Runtime.CompilerServices.ExtensionAttribute”。 Use the 'this' keyword instead改用“this”关键字

And even if we could, we can't place it on the Program class itself即使我们可以,我们也不能将它放在Program class 本身

TL;DR : The C# compiler doesn't recognize that there are extension methods in the top level statements, and as such doesn't apply the necessary [Extension] attribute to the class or the method TL;DR :C# 编译器无法识别顶级语句中有扩展方法,因此不会将必要的[Extension]属性应用于 class 或方法

To attempt and answer to my own question with a suspicion.带着怀疑来尝试和回答我自己的问题。

I wonder if this was a design choice, and that top-level methods are analogous to Local Functions from C# 7.我想知道这是否是一种设计选择,顶级方法类似于 C# 7 中的局部函数

With a local function, methods are also compiled into the class but outside of the method they are defined in the source code.使用本地 function,方法也被编译到 class 但在源代码中定义的方法之外。 The generated method names also look very similar, like <$Main>g__Test .生成的方法名称看起来也非常相似,例如<$Main>g__Test

Attempting to write the same extension method as a local function gives me the same compiler error:尝试编写与本地 function 相同的扩展方法会给我相同的编译器错误:

局部函数错误 CS1106:扩展方法必须在非泛型静态类中定义

According to Mads Torgersen in this video from .NET Conf 2020 any functions declared as top-level statements are local functions within the main() method, rather than methods on the Program class.根据.NET Conf 2020 的这段视频中的 Mads Torgersen 所说,任何声明为顶级语句的函数都是main()方法中的本地函数,而不是Program class 中的方法。

Local functions cannot be extension methods.本地函数不能是扩展方法。

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

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