C# 8.0、C# 9.0和C# 10.0中增加了很多新語法,這些新語法能夠幫助開發人員更好地編寫代碼。
1.頂級語句(top-level statements)
以前Program.cs進入點都會是長一長串,C# 10之後可以大幅縮減程式碼,對剛入門也比較友善一些,(應該是吧
// C# 10之前
using System;
namespace Application
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
// C# 10之後
Console.WriteLine("Hello, World!");
雖然程式碼大幅縮減但反編譯後的代碼Main卻依然存在只是開發人員在開發時比較簡化而已。
[CompilerGenerated]
internal class Program
{
private static void <Main>$(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
2.全局 using 指示詞
再編寫程式時常常會用到許多重複的命名空間,C# 10新增了方便管理的方式全局using可以新增一個*.cs檔,在程式中聲明
global using Microsoft.Data.Sqlite;
global using System.Text.Json;
這樣之後只要是在同個項目中的所有*.cs都可以使用以上命名空間,不須而外在聲明。
3.using 陳述式
過去使用using需要用大擴號包起來,C# 8.0之後可以不需要包起來就能使用,但要注意由於釋放資源便由系統決定不向過去由開發人員自己定義範圍,如要使用新版方式也是有其他解決方案如下
// C# 8.0之前
using (var conn = new SqlConnection(connStr))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from T_Articles";
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read()){}
}
}
}
// C# 8.0之後
using var conn = new SqlConnection(connStr);
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "select * from T_Articles";
using var reader = cmd.ExecuteReader();
while (reader.Read()){}
// 此程序會出錯第4行如下異常:System.IO.IOException:“The process cannot access the file 'e:\1.txt'because it is being used by another process.”
// 解決方式
{
using var outStream = File.OpenWrite("e:/1.txt");
using var writer = new StreamWriter(outStream);
writer.WriteLine("hello");
}
string s = File.ReadAllText("e:/1.txt");
Console.WriteLine(s);
4.命名空間聲明範圍
// C# 10之前
namespace TMS.Admin{
class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
}
}
// C# 10之後
namespace TMS.Admin;
class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
}
5.可為空的引用類型
C# 8.0中提供了“可為空的引用類型”語法,可以在引用類型後添加“?”修飾符聲明這個類型是可為空的。對於沒有添加“?”修飾符的引用類型的變量,當編譯器發現存在為這個變量賦值null的可能性的時候,編譯器會給出警告信息。
項目*.csproj文件中的<Nullable>disable</Nullable>或改enable來設定,參考。
Student s1 = GetData();
Console.WriteLine(s1.Name.ToLower());
// ↓ 提示可能為空的警告訊息,如果沒有再GetData PhoneNumber設定值則會出錯(Object reference not set to an instance of an object.)
Console.WriteLine(s1.PhoneNumber.ToLower());
Student GetData()
{
Student s1 = new Student("Zack");
s1.PhoneNumber = "999";
return s1;
}
// string? 聲明可為null
public class Student
{
public string Name { get; set; }
public string? PhoneNumber { get; set; }
public Student(string name)
{
this.Name = name;
}
}
6.必要修飾詞(required)
// 在new student時一定要先將被聲明為required屬性先創建,否則會錯誤
Student s1 = new Student() {
Name = "Joy",
PhoneNumber = "0937"
};
public class Student
{
public required string Name { get; set; }
public required string PhoneNumber { get; set; }
}
7.record類型用法
// 將兩個同樣record修改部分內容寫法
User u1 = new User("Zack", "yzk@example.com", 18);
User u2 = new User(u1.UserName, "test@example", u1.Age);
// 可以透過with縮減程式碼打成上述結果
User n1 = new User("Zack", "yzk@example.com", 18);
User n2 = n1 with { Email= "test@example" };
Console.WriteLine(u2);
Console.WriteLine(u1);
Console.WriteLine(Object.ReferenceEquals(u1,u2)); //False
Console.WriteLine(n2);
Console.WriteLine(n1);
Console.WriteLine(Object.ReferenceEquals(n1,n2)); //False
public record User(string UserName, string Email, int Age);