首页 > 编程语言 >C#9.0新特性详解系列之四:顶级程序语句(Top-Level Programs)

C#9.0新特性详解系列之四:顶级程序语句(Top-Level Programs)

时间:2024-03-24 11:33:06浏览次数:32  
标签:语句 args 顶级 C# Top Programs static Main 代码

原文链接:https://www.cnblogs.com/markkang/p/14091908.html

1 背景与动机
通常,如果只想用C#在控制台上打印一行“Hello World!”,这可不是Console.WriteLine("Hello World!");一条语句就可以搞定的,还涉及到其他必要基础代码(如定义类和入口函数Main),例如下面:

using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello World!");
}
}
就打印一句“Hello World!”,就这么多代码。这个不仅对于初学者来说麻烦,而且使得代码凌乱,并且增加了缩进层级。为了解决这些问题,就提出了顶级代码语句这个新特性。

2 顶级语句
2.1 介绍
在C#9.0中,将Class的定义和主函数Main的声明省略掉,只写出你的核心业务代码,就成了顶级语句。上面这段代码,我们可以用顶级语句写为:

using System;

Console.WriteLine("Hello World!");
这样,代码简洁清晰了很多,易于初学者理解。是不是有点写Python的感觉?当然,任何语句都是允许的。如果你想返回值,你可以那样做;你想用await,也可以那样做;如果你想访问命令行参数,args也是可用的;你想使用本地函数,也是可以的。

虽然可以使用任何代码,但是有一些规则要求必须遵守:

顶级语句必须放在using语句代码后面

顶级语句必须用在任何类型或者命名空间声明的前面

顶级语句只能写在一个源代码文件里,像如今只能写一个main方法一样。

顶级语句中定义的本地函数和变量,在顶级代码段外部的任何地方调用他们都会产生错误。

下面这段代码就是一个比较好的示例:

using static System.Console;
using System.Threading.Tasks;

WriteLine("Hello,");
Print(args[0]);
await Task.Delay(1000);
return 0;

void Print(string arg)
{
WriteLine(arg);
}
2.2 原理
我们知道,C#作为面向对象的编程语言,一切类型都是面向对象的,要有类型和成员定义。顶级语句表面看着好像违反了这一规则,实际上没有。这是因为,顶级语句最终还是在编译的时候,被作为全局命空间中Program类的Main方法体中一段代码一起自动生成。如下所示:

static class Program
{
static async Task Main(string[] args)
{
// 顶级语句
}
}
需要注意的是,这里的类名Program和方法名Main只是用来举例,其实在编译器生成的不是这个名字。我们可以通过查看IL代码确认这一点:


根据在顶级语句中是否有异步操作和返回值的情况,生成的入口函数签名也是不同的。具体如下面表格所示:

存在返回值 不存在返回值
存在异步 async static Task<int> Main(string[] args) async static Task Main(string[] args)
不存在异步 static int Main(string[] args) static void Main(string[] args)
例如上面代码,生成的入口函数<Main>$就如下代码所示:

static class Program
{
async static Task<int> Main(string[] args)
{
WriteLine("Hello");
Print(args[0]);
await Task.Delay(1000);
return 0;

void Print(string arg)
{
WriteLine(arg);
}
}
}
3 结束语
使用顶级语句能简化我们的编码工作,使代码看起来简洁清晰,对初学者也很友好,本质上也未改变C#的语言的原有的语法结构,任何语句都可以使用,没有产生额外的限制,从这些方面来说,是一个值得肯定的变化。

标签:语句,args,顶级,C#,Top,Programs,static,Main,代码
From: https://www.cnblogs.com/Dongmy/p/18092207

相关文章

  • PTA基础编程练习题目集 7—4 BCD解密
    题目描述:BCD数是用一个字节来表达两位十进制的数,每四个比特表示一位。所以如果一个BCD数的十六进制是0x12,它表达的就是十进制的12。但是小明没学过BCD,把所有的BCD数都当作二进制数转换成十进制输出了。于是BCD的0x12被输出成了十进制的18了!现在,你的程序要读入这个错误的十进......
  • 阿里二面:谈谈ThreadLocal的内存泄漏问题?问麻了。。。。
    引言ThreadLocal在Java多线程编程中扮演着重要的角色,它提供了一种线程局部存储机制,允许每个线程拥有独立的变量副本,从而有效地避免了线程间的数据共享冲突。ThreadLocal的主要用途在于,当需要为每个线程维护一个独立的上下文变量时,比如每个线程的事务ID、用户登录信息、数据库连接......
  • CF1861C Queries for the Array
    CF1861CQueriesfortheArray不太一样的写法,感觉比较容易理解一点。码量也比较短。首先我们要发现:一个序列如果目前是升序的,那么它不管删多少个数(中间不再加数),最终还是升序的;如果目前不是升序,那么不管加多少个数,最终也不是升序。这启发我们用两个数组\(up_i\)和\(down_i\)......
  • CF1420D & 102012G [线段交集问题]
    CF1420DRescueNibel!首先要发现一个性质:如果一些线段有交集,那么交集一定是条线段,并且一定有其中一条线段的左端点是交集的左端点。所以方案可以转化为求其中一条线段的左端点是交集的左端点的方案数。这启发我们枚举每个点作为交集的左端点,计算至少有一条线段的左端点是这个......
  • 扔掉print,用icecream来调试你的代码
    print是我们平时写些python小工具时,最常用的调试工具。因为开发代码时,常常通过print将执行流程、变量的值以及其他关键信息输出到控制台来观察,以便了解程序执行情况和调试bug。但是,print的输出过于简单,在输出变量内容,函数调用,执行过程等相关信息时,往往需要自己手动去补充很多的输......
  • P9755 [CSP-S 2023] 种树
    P9755[CSP-S2023]种树首先,容易看出单调性,可以对最少天数二分。转为判定性问题后,我们思考如何判定。对于每棵树,都可以从刚种下长到最后一天。我们由此可以写出\(calc(i,l,r)\)表示第\(i\)棵树从第\(l\)天长到第\(r\)天的高度。\(calc(i,l,r)=\sum\limits_{i=l}^r\max(......
  • 在Linux中,`/etc/passwd` 和 `/etc/shadow` 文件分别有什么作用?
    在Linux系统中,/etc/passwd和/etc/shadow文件是用于存储系统用户账户信息的关键配置文件,它们各自扮演不同的角色,共同管理系统的用户身份验证和密码安全性。/etc/passwd文件:作用:存储了系统中的每个用户的基本信息,包括用户名、用户ID(UID)、组ID(GID)、用户信息描述(GECOS)、用......
  • NVIDIA 2024 GTC大会提出的数字孪生技术 —— 工厂3D仿真与AI大模型结合
    地址:https://www.youtube.com/watch?v=JQdyzQdMRS0FusingReal-TimeAIWithDigitalTwins......
  • 构建自定义颜色的SolidColorBrush
    ①System.Windows.Media.Brushes.BlueViolet;②newSystem.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(0X8A,0X2B,0XE2));③newSystem.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(0XFF,0X8A,0X2B,0XE2));//完全......
  • torch.sin( )参数详解
    功能介绍:torch.sin()是PyTorch提供的一个函数,用于计算输入张量中元素的正弦值。它的功能非常简单,就是将输入张量中每个元素的值作为角度,计算其对应的正弦值。具体来说,torch.sin()函数接受一个张量作为输入,并返回一个张量,其中每个元素是输入张量中对应元素的正弦值。代码......