Open WangShuXian6 opened 1 year ago
HelloWorld.cs
class HelloWorld
{
static void Main()
{
System.Console.WriteLine("hello world");
}
}
C#是区分大小写的语言,大小写不正确会使代码无法成功编译。
写好C#代码后需要编译和运行。这时要选择使用哪个.NET实现(或者说.NET框架)。这些实现通常打包成一个软件开发包(Software Development Kit,SDK),其中包括编译器、运行时执行引擎、“运行时”能访问的语言可访问功能框架,以及可能和SDK捆绑的其他工具(比如供自动化生成的生成引擎)。由于C#自2000年便已公布,目前有多个不同的.NET框架供选择
取决于开发的目标操作系统以及你选择的.NET框架,每种.NET框架的安装过程都有所区别。有鉴于此,建议访问https://dotnet.microsoft.com/download 了解具体的下载和安装指示。如有必要,先选好.NET框架,再根据目标操作系统选择要下载的包。
如不确定要使用的.NET框架,就默认选择.NET Core。它可运行于Linux、macOS和Microsoft Windows,是.NET开发团队投入最大的实现。另外,由于它具有跨平台能力,所以优先使用.NET Core
dotnet命令dotnet.exe是dotnet命令行接口(或称dotnet CLI),可用于生成C#程序的初始代码库并编译和运行程序 [3] 。注意这里的CLI代表“命令行接口”(Command-Line Interface)。为避免和代表“公共语言基础结构”(Common Language Infrastructure)的CLI混淆,本书在提到dotnet CLI时都会附加dotnet前缀。无dotnet前缀的CLI才是“公共语言基础结构”。安装好之后,验证可以在命令行上执行dotnet。
.在HelloWorld目录中执行dotnet new console命令来生成程序基架(或称程序项目)。这会生成几个文件,最主要的是Program.cs和项目文件:
dotnet new console
运行生成的程序。这会编译并运行由dotnet new console命令创建的默认Program.cs程序。程序内容和代码清单1.1相似,只是输出变成“Hello World!”。 虽然没有显式请求、编译(或生成)程序项目,但dotnet run命令在执行时隐式执行了这一步
dotnet run
编辑Program.cs文件,重新运行程序:
dotnet run
无论dotnet CLI还是Visual Studio都会自动创建几个文件。第一个是名为Program.cs的C#文件。虽然可选择任何名称,但一般都用Program这一名称作为控制台程序起点。.cs是所有C#文件的标准扩展名,也是编译器默认要编译成最终程序的扩展名
语言对比:Java——文件名必须匹配类名 Java要求文件名和类名一致。C#虽然也常遵守这一约定,却并非必需。在C#中,一个文件可以包含多个类。而且从C# 2.0开始,类的代码可通过所谓的分部类拆分到多个文件中。你了解得越多,就越有能力针对特定应用程序的需求做出最合适的体系结构选择。
虽然并非一定需要,但通常都会为C#项目生成一个项目文件。项目文件的内容随不同应用程序类型和.NET框架而变。但至少会指出哪些文件要包含到编译中、要生成什么应用程序类型(控制台、Web、移动、测试项目等)、支持什么.NET框架、调试或启动应用程序需要什么设置,以及代码的其他依赖项(称为库)。例如,代码清单1.2列出了前面刚创建过的.NET Core控制台应用的项目文件。
C#.csproj
<Project Sdk="Microsoft.NET.Sdk">
>注意应用程序标识为.NET Core版本8.0(net8.0)的控制台应用(Exe)。其他所有设置(比如要编译哪些C#文件)则沿用默认值。例如,和项目文件同一目录(或子目录)中的所有*.cs文件都会包含到编译中。
### 编译和执行
>dotnet build命令生成名为HelloWorld.dll的程序集 (assembly) [[6]](javascript:void(0)) 。扩展名.dll代表“动态链接库”(Dynamic Link Library,DLL)。对于.NET Core,所有程序集都使用.dll扩展名。控制台程序也不例外,就像本例这样。.NET Core应用程序的编译输出默认放到子目录./bin/Debug/netcoreapp3.1/。之所以使用Debug这个名称,是因为默认配置就是debug。该配置造成输出为调试进行优化,而不是为性能而优化。编译好的输出本身不能直接执行。相反,需用CLI来寄宿(host)代码。对于.NET Core应用程序,这要求dotnet.exe进程作为应用程序的寄宿进程。这就是为什么总是需要用dotnet run命令来运行应用程序。必要时也可以将应用程序及其所需的运行时文件打包在一起,生成一个可以独立运行且无须另外安装dotnet运行时库可执行文件。具体方法请参考后面的高级主题“发布可独立运行的可执行文件”。
#### 高级主题:发布可独立运行的可执行文件
>生成一个可以独立运行,而不依赖于dotnet命令的可执行文件是完全可行的。
>要做到这一点,需要执行dotnet publish命令,并且通过命令参数`--runtime(-r)`来指定需要兼容的目标平台。
>例如,如需兼容大部分Linux平台,可以在CSPROJ文件所在的目录下执行上述命令,并使用`linux-x64`参数:
```bash
dotnet publish --runtime linux-x64
执行上述命令后,会生成一个目录
(./bin/Debug/netcoreapp3.1/linux-x64/publish/)
,里面包含了运行HelloWorld程序所需的所有文件。有了这些便不需要在目标平台事先安装dotnet运行时库。 若要运行HelloWorld程序,只需要直接运行其可执行文件即可bin\Release\net8.0\linux-x64\publish\HelloWorld
(在Windows上,可执行文件会带有扩展名“.exe”,但是在运行可执行文件时不需要写出该扩展名。)需要注意的是,在上面的示例中生成的可执行文件只能在linux-x64兼容平台上运行。若要支持更多其他平台,则需要为每一个平台生成对应的可执行文件。除了Linux之外,其他目标平台还包括win-x64和osx-x64等。(访问网址http://itl.tc/ridcatalog 可以查看兼容平台的完整列表。)
按照前面的方法生成的目录里面,除了应用程序自己的可执行文件之外,还有将近200个依赖文件。实际上也可以生成单一的可独立运行的文件。若要生成单一文件,需要为生成命令加上
-p:PublishSingleFile=true
参数:dotnet publish --runtime linux-x64 -p:PublishSingleFile=true
要用dotnet CLI生成并执行代码,请打开命令提示符,将当前目录设为EssentialCSharp.sln文件所在的目录。执行dotnet build命令编译所有项目
要运行特定项目的源代码,导航到项目文件所在目录并执行dotnet run命令。另外,在任何目录都可以执行dotnet run-p
命令。其中 是要执行的项目文件的路径(例如dotnet run-p .\src\Chapter01\Chapter01.csproj)。随后会运行程序,并提示运行的是哪个代码清单。 要执行测试,在相应目录中执行dotnet test命令(在EssentialCSharp.sln所在目录执行该命令,则所有单元测试都会执行)
关键字
为了帮助编译器解释代码,C#中的某些单词具有特殊地位和含义,它们称为关键字 。编译器根据关键字的固有语法来解释程序员写的表达式。在HelloWorld程序中,class、static和void均是关键字。
编译器根据关键字识别代码的结构与组织方式。由于编译器对这些单词有着严格的解释,所以只能将关键字放在特定位置。如违反规则,编译器会报错。
https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/
bstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum
event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long
namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc
static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void volatile while
上下文关键字 上下文关键字用于在代码中提供特定含义,但它不是 C# 中的保留字。 一些上下文关键字(如 partial 和 where)在两个或多个上下文中有特殊含义。
add and alias ascending args async await by descending dynamic equals from
get global group init into join let 托管(函数指针调用约定) nameof nint not
notnull nuint on or orderby partial(类型) partial(方法) record remove select
set 非托管(函数指针调用约定) unmanaged(泛型类型约束) value var when(筛选条件) where(泛型类型约束) where(查询子句) with yield
请参阅 C# 参考
C# 1.0之后没有引入任何新的保留关键字 ,但在后续版本中,一些构造使用了上下文关键字 ,它们在特定位置才有意义,在其他位置则无意义。这样大多数C# 1.0代码都能兼容后续版本
C#用标识符标识程序员编码的构造 HelloWorld和Main均为标识符。分配标识符之后,以后将用它引用所标识的构造 开发者应分配有意义的名称,不要随性而为
好的程序员总能选择简洁而有意义的名称,这使代码更容易理解和重用。 “框架设计准则”(http://t.cn/RD6v4RB )建议不要在标识符中使用单词缩写 [3] ,甚至不要使用不被广泛接受的首字母缩写词。 为避免滥用,可限制所有首字母缩写词都必须包含到术语表中。
标识符有两种基本的大小写风格。
第一种风格被.NET框架创建者称为Pascal大小写 (PascalCase),这是因为它曾经在Pascal编程语言中很流行,它要求标识符的每个单词首字母大写,例如ComponentModel、Configuration和HttpFileCollection。注意在HttpFileCollection中,由于首字母缩写词HTTP的长度超过两个字母,所以仅首字母大写。
第二种风格是camel大小写 (camelCase),除第一个字母小写,其他约定一样,例如quotient、firstName、httpFileCollection、ioStream和theDreadPirateRoberts。
·要更注重标识符的清晰而不是简短。
·不要在标识符名称中使用单词缩写。
·不要使用不被广泛接受的首字母缩写词,对于那些已经被广泛接受的缩写词,在使用时也要保持一致。
下划线虽然合法,但标识符一般不要包含下划线、连字号或其他非字母/数字字符。此外,C#不像其前辈那样使用匈牙利命名法(为名称附加类型缩写前缀)。这避免了数据类型改变时还要重命名变量,也避免了数据类型前缀经常不一致的情况。
极少数情况下,有的标识符(比如Main)可能在C#语言中具有特殊含义。
·要把两个字母的首字母缩写词全部大写,除非它是camelCase标识符的第一个单词。
·包含三个或更多字母的首字母缩写词,仅第一个字母才要大写,除非该缩写词是camelCase标识符的第一个单词。
·在camelCase标识符开头的首字母缩写词中,所有字母都不要大写。
·不要使用匈牙利命名法(不要为变量名称附加类型前缀)。
虽然罕见,但关键字附加“@”前缀可作为标识符使用,例如可命名局部变量@return。类似地(虽不符合C#大小写规范),也可将方法命名为@throw()并且跟随一对括号,形如:@throw()。
在Microsoft的实现中,还有4个未文档化的保留关键字:arglist,makeref,reftype,refvalue。它们仅在罕见的互操作情形下才需要使用,平时完全可以忽略。注意这4个特殊关键字以双下划线开头。C#设计者保留将来把这种标识符转化为关键字的权利。为安全起见,自己不要创建这样的标识符。
C#所有代码都出现在一个类定义的内部,最常见的类定义以关键字class开头。 类定义 是class identifier {...}形式的代码块。
类名称(本例是HelloWorld)可以随便取,但根据约定,它应当使用PascalCase风格。 就本例来说,可选择的名称包括Greetings、HelloInigoMontoya、Hello或者简单地称为Program。(对于包含Main()方法的类,Program是个很好的名称。Main()方法的详情稍后讲述。)
基本的类声明
class HelloWorld { //... }
·要用名词或名词短语命名类。
·要为所有类名使用PascalCase大小写风格。
程序通常包含多个类型,每个类型包含多个方法。
语法上说,C#方法 是已命名代码块,由一个方法声明(例如static void Main())引入,后跟一对大括号({}),其中包含零条或多条语句。方法可执行计算或操作。与书面语言中的段落相似,方法提供了结构化和组织代码的一种方式,使之更易读。更重要的是,方法可以重用,可从多个地方调用,所以避免了代码的重复。方法声明除了引入方法并定义方法名,还要定义传入和传出方法的数据。在代码清单1.4中,Main()连同后面的{...}便是C#方法的例子。
C#程序从Main方法开始执行。该方法以static void Main()开头。在命令控制台中输入dotnet run HelloWorld.exe执行程序时,程序将启动并解析Main的位置,然后执行其中第一条语句。如代码清单1.4所示。
class HelloWorld { static void Main() { System.Console.WriteLine("hello");
}
}
>虽然Main方法声明可进行某种程度的变化,但关键字static和方法名Main是始终都需要的。
#### Main方法声明
>C#要求Main方法返回void或int,而且要么无参,要么接收一个字符串数组。代码清单1.5展示了Main方法的完整声明。
>带有参数和返回类型的Main方法
```c#
class HelloWorld
{
static void Main(string[] args)
{
System.Console.WriteLine("hello");
}
}
args参数是用于接收命令行参数的字符串数组。 但数组第一个元素不是程序名称,而是可执行文件名称 后的第一个命令行参数,这和C和C++不同。 用System.Environment.CommandLine获取执行程序所用的完整命令。
Main返回的int是状态码,标识程序执行是否成功。返回非零值通常意味着错误。
Main返回的int是状态码,标识程序执行是否成功。返回非零值通常意味着错误。此外,从C#7.1开始,Main方法也支持async/await修饰词。
与C风格的“前辈”不同,C#的Main方法名使用大写M,和C#的PascalCase命名约定一致。
将Main方法指定为static意味着这是“静态”方法,可用类名.方法名的形式调用。若不指定static,用于启动程序的命令控制台还要先对类进行实例化 ,然后才能调用方法。
Main()之前的void表明方法不返回任何数据
C#和C/C++一样使用大括号封闭构造(比如类或者方法)的主体。例如,Main方法主体就是用大括号封闭起来的。本例方法主体仅一条语句。
C#
.NET SDK C:\program files\dotnet\sdk{version}\
.NET 运行时 C:\program files\dotnet\shared{runtime-type}{version}\