为什么我不能在 C# 9 中定义顶级扩展方法?
Why can't I define top-level extension methods in C# 9?
我曾认为使用 C# 9 中的 Top-Level Statements 功能本质上是将您的顶级代码包装在通常的 Program
class 和 Main
方法中。
一个反编译的顶层程序是这样的:
[CompilerGenerated]
internal static class $Program
{
private static void $Main(string[] args)
{
// top-level code here
}
}
您可以在顶层定义普通方法。它们被编译到 Program
class 中,但在 Main
方法之外,其中也可以定义扩展方法。
因为生成的 Program
class 是静态的和非泛型的,我希望能够在顶层定义扩展方法。但是,我收到编译器错误 CS1106: Extension method must be defined in a non-generic static class
这是为什么?
顶级语句功能按照您描述的方式实现:您的顶级代码被包装到编译器生成的class和Main
方法.
无法在此 Main
方法中声明您的扩展,因此您的语法无效。扩展声明不是顶级声明。
使用 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.
这是顶层生成的代码Hello World
(为了简洁省略了一些东西,完整的东西here)
[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");
}
}
下面是带有扩展方法的 class 的反编译代码:
[Extension]
internal static class Foo
{
[Extension]
private static void WriteToConsole(string source)
{
Console.WriteLine(source);
}
}
似乎编译器没有识别出有扩展方法,因此没有正确编译它。我们也不能强行放置 Extension
属性,因为这样我们会收到一个错误提示
error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead
即使可以,我们也不能将其放在 Program
class 本身上
TL;DR:C# 编译器无法识别顶级语句中的扩展方法,因此不应用必要的 [Extension]
属性到 class 或方法
带着怀疑尝试回答我自己的问题。
我想知道这是否是一种设计选择,顶级方法类似于 C# 7 中的 Local Functions。
对于局部函数,方法也被编译到 class 但在方法之外,它们在源代码中定义。生成的方法名看起来也很相似,比如 <$Main>g__Test
.
尝试编写与本地函数相同的扩展方法时出现相同的编译器错误:
When the first parameter of a method includes the this
modifier, that method is said to be an extension method. Extension methods can only be declared in non-generic, non-nested static classes.
根据语言规范,扩展方法必须在静态 class.
中 声明
将顶级方法实现 放在隐藏的静态class 中并不重要。顶级方法(根据定义)未在 any class 中声明,因此根据规范不能是扩展方法。
与所有语言设计问题一样,这是因为这是语言设计团队设计语言的方式。据推测,阻止您在非静态 classes 中定义扩展方法的同样问题也适用于顶级方法。
如果您希望有更多权限的人提供更多详细信息,您可以在 csharplang repo or ask a question on Gitter 中发起讨论。
根据 Mads Torgersen 在 this video from .NET Conf 2020 中声明为顶级语句的任何函数都是 main()
方法中的局部函数,而不是 Program
class 中的方法.
局部函数不能是扩展方法。
我曾认为使用 C# 9 中的 Top-Level Statements 功能本质上是将您的顶级代码包装在通常的 Program
class 和 Main
方法中。
一个反编译的顶层程序是这样的:
[CompilerGenerated]
internal static class $Program
{
private static void $Main(string[] args)
{
// top-level code here
}
}
您可以在顶层定义普通方法。它们被编译到 Program
class 中,但在 Main
方法之外,其中也可以定义扩展方法。
因为生成的 Program
class 是静态的和非泛型的,我希望能够在顶层定义扩展方法。但是,我收到编译器错误 CS1106: Extension method must be defined in a non-generic static class
这是为什么?
顶级语句功能按照您描述的方式实现:您的顶级代码被包装到编译器生成的class和Main
方法.
无法在此 Main
方法中声明您的扩展,因此您的语法无效。扩展声明不是顶级声明。
使用 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.
这是顶层生成的代码Hello World
(为了简洁省略了一些东西,完整的东西here)
[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");
}
}
下面是带有扩展方法的 class 的反编译代码:
[Extension]
internal static class Foo
{
[Extension]
private static void WriteToConsole(string source)
{
Console.WriteLine(source);
}
}
似乎编译器没有识别出有扩展方法,因此没有正确编译它。我们也不能强行放置 Extension
属性,因为这样我们会收到一个错误提示
error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead
即使可以,我们也不能将其放在 Program
class 本身上
TL;DR:C# 编译器无法识别顶级语句中的扩展方法,因此不应用必要的 [Extension]
属性到 class 或方法
带着怀疑尝试回答我自己的问题。
我想知道这是否是一种设计选择,顶级方法类似于 C# 7 中的 Local Functions。
对于局部函数,方法也被编译到 class 但在方法之外,它们在源代码中定义。生成的方法名看起来也很相似,比如 <$Main>g__Test
.
尝试编写与本地函数相同的扩展方法时出现相同的编译器错误:
When the first parameter of a method includes the
this
modifier, that method is said to be an extension method. Extension methods can only be declared in non-generic, non-nested static classes.
根据语言规范,扩展方法必须在静态 class.
中 声明将顶级方法实现 放在隐藏的静态class 中并不重要。顶级方法(根据定义)未在 any class 中声明,因此根据规范不能是扩展方法。
与所有语言设计问题一样,这是因为这是语言设计团队设计语言的方式。据推测,阻止您在非静态 classes 中定义扩展方法的同样问题也适用于顶级方法。
如果您希望有更多权限的人提供更多详细信息,您可以在 csharplang repo or ask a question on Gitter 中发起讨论。
根据 Mads Torgersen 在 this video from .NET Conf 2020 中声明为顶级语句的任何函数都是 main()
方法中的局部函数,而不是 Program
class 中的方法.
局部函数不能是扩展方法。