这篇笔记我们介绍C#语言的基本语法,我们从一个简单的Hello World程序开始逐步介绍代码的每个部分。由于C#语法大部分和Java非常类似,因此本章节会着重介绍C#和Java间有区别的部分,因此学习本章节前有一定的Java基础是最好的。
下面代码是一个最简单的Hello World程序,代码编译执行后会在控制台上输出一行"Hello, world!
字符串。
using System;
namespace Gacfox.Demo.DemoNetCore
{
class Program
{
static void Main()
{
Console.WriteLine("Hello, world!");
}
}
}
第一行使用了using
语句,后面的System
是一个命名空间,这条语句告知编译器程序使用System
命名空间,因为在随后的代码中我们用到了System.Console
这个类。namespace
语句声明了我们自己代码所使用的命名空间为Gacfox.Demo.DemoNetCore
。随后我们定义了一个名为Program
的类,并定义了Main()
方法,也是C#中的入口方法。方法内部,我们调用了Console
类的WriteLine
方法,输出了一行文本。
C#9引入了顶级语句的写法,我们可以不再编写Main
方法和其外层的类了。
Program.cs
using System;
Console.WriteLine("Hello, world!");
代码中,我们的Program.cs
文件仅仅包含一条代码,而没有编写任何的Main
方法。
但我们要注意,使用顶级语句有一些限制:
args
变量读取命令行参数,类似Main
方法的string[] args
参数。await
关键字调用异步方法。return
进程的退出代码,和Main
方法相同。从上面例子程序中,我们可以看出C#语言代码规范上和Java的一些差异。
首先,C#提倡对于局部变量和私有成员变量使用lowerCamelCase
,其余(包括公开的成员变量、方法名、类名、命名空间)使用PascalCase
,这和Java不同。注意C#中的入口方法Main
也是PascalCase
的,如果你错写成了lowerCamelCase
是无法编译通过的,报错原因是找不到可执行程序的入口方法。
另外,C#建议代码的左大括号换行;而Java则恰好相反,提倡左大括号不换行,以提高代码排版的密度便于阅读。实际上两者各有各的好处,我们使用不同的编程语言开发就要入乡随俗,遵循一个大多数人都认可的标准,这样也省去了调试开发工具的代码格式化器的麻烦。
C#中,命名空间相当于Java的包(package)。
上面的例子程序中,有这样一句:
using System;
因为我们要使用System.Console
这个类的WriteLine()
函数,因此引入了System
这个命名空间。如果不引入,我们使用Console
时,就必须写它的全限定类名System.Console.WriteLine()
了。
对于我们自己的代码,创建命名空间则需要使用namespace
关键字:
namespace Gacfox.Demo.DemoNetCore
{
namespace Project {}
}
namespace可以用大括号嵌套,命名规则通常约定为公司名.项目名.子系统名
,其中是可以包含点号的,例如:namespace Gacfox.DemoProject.FirstDemo {}
。另外要注意,命名空间要遵循首字母大写的规范。
C#10版本引入了文件全局命名空间的语法:
namespace Gacfox.Demo.DemoNetCore;
在文件开头这样编写,该文件的所有代码就都会位于Gacfox.Demo.DemoNetCore
命名空间下,这种写法更加简洁,避免了太多无意义的大括号嵌套因此可读性更好,推荐在高版本的C#开发中使用。不过注意该语法在同一个文件中不可以和大括号语法混合使用。
C#命名空间和Java包的区别:Java的包结构和源代码结构都统一使用文件路径与文件名组织,简单粗暴而且高效;C#使用namespace关键字组织命名空间结构,而源代码路径则由构建工具搜索识别,类名和.cs
文件名也可以不同,更加灵活。
C#支持3种风格的注释:单行注释、多行注释和XML文档注释。
单行注释使用两个斜线表示,例子如下。
// 这是单行注释
多行注释使用一对/* */
表示,其中的内容可以跨越多行。
/*
这是
多行
注释
*/
C#的XML文档注释使用三个斜线///
开头,所谓的文档注释类似Java的JavaDoc注释,标注在类和方法上用于生成API文档,在Visual Studio中编写良好的文档注释也会以恰当的方式在代码自动补全框中展现。和Java不同的是C#的文档注释内部包含一系列XML标签来指定文档的各个字段。比较常用的文档注释例子如下:
/// <summary>
/// 两个 <see langword="int" /> 类型整数相加,返回其结果。
/// </summary>
/// <param name="a">被加数</param>
/// <param name="b">加数</param>
/// <returns>两个整数之和</returns>
int Add(int a, int b) { }
<summary>
:该标签包含函数的摘要信息,该字段应尽量简短的一句话描述函数的功能。<param name="">
:该标签描述函数的参数信息,name
属性为参数名。<returns>
:该标签描述函数的返回值。上面注释中,我们还用到了<see>
标签,它用于在说明中插入,该标签支持两个属性:
langword
:用于引用C#关键字,常用的包括类似true
、int
等。cref
:用于引用自定义类型,必要时还需要引入类的命名空间。实际上,C#的文档注释功能是十分强大的,除了上述提到的几种标签,还有许多其它有用的标签:
<remarks>
:类似于<summary>
,用于附加说明,内部可以用<para>
标签进行文本的分段。<code lang="">
:用于附加使用示例代码,code
属性标注语言,用于指示API文档渲染时的代码高亮。C#的文档注释固然功能强大,但实际使用起来,如果把上面提到的所有标签都在每一个函数上完整的编写,可能造成一个C#源代码文件里充斥丑陋的XML标签,可读性反而很低的窘境。良好的代码应该是自描述的,我们实际开发中应该适度注释,避免像网络小说水字数一样无意义的占用篇幅。