文章目录
- 顶级语句
- 全局using 指令
- Using资源管理
- 文件范围的命名空间声明
- 可空的引用类型
- 记录(record)类型
顶级语句
C#9.0中直接在C#文件中直接编写入口方法的代码,不用类,不用Main。同一个项目中只能有一个文件具有顶级语句。顶级语句中可以直接使用await
语法,也可以声明函数。
全局using 指令
C#10中
1、将 global 修饰符添加到 using 前,这个命名空间就应用到整个项目,不用重复using。
2、通常创建一个专门用来编写全局using代码的C#文件。
3、如果csproj中启用了enable,编译器会自动隐式增加对于System、System.Linq等常用命名空间的引入,不同各类型项目引入的命名空间也不一样。
Using资源管理
在C#8中实现了Idisposable
/IAsyncDisposable
接口的类型的变量声明前加上using
,当代码执行 离开变量的作用域时,对象就会被释放。
using SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=db1;Integrated Security=True") ;
conn.Open();
using SqlCommand cmd = conn.CreateCommand() ;
cmd.CommandText = "select * from T_Articles";
using SqlDataReader reader = cmd.ExecuteReader() ;
while (reader.Read())
{
string title = reader.GetString(reader.GetOrdinal("Title"));
Console.WriteLine(title);
}
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);
//以上代码在同一个方法中会发生异常,可以采用原始的using大括号方式释放资源 或者 用代码块方式
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);
{
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);
文件范围的命名空间声明
在之前版本的C#中,类型必须定义在namespace中,从c#10开始可以采用如下写法,减少namespace的大括号嵌套
namespace ConsoleApp2;
internal class MyTable
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
public override string ToString()
{
return "Id:" + this.Id + ",Name:" + this.Name + ",Birthday:" + this.Birthday.ToString();
}
}
可空的引用类型
如果不注意检查引用类型变量是否可空,就有可能造成程序中出现
NullReferenceException
异常。
1、csproj中<Nullable>enable</Nullable>
启用可空引用类型检查。
2、在引用类型后添加“?”修饰符来声明这个类型是可空的。对于没有添加“?”修饰符的引用类型的变量,如果编译器发现存在为这个变量赋值null的可能性的时候,编译器会给出 警告信息。
internal class Person
{
public string Name { get; set; }
public string Phone { get; set; }
public Person(string name)
{
this.Name = name;
}
}
如果确认被访问的变量、成员确实不会出现为空的情况,也可以在访问可空的变量、成员的时候加上
!
来抑制编译器的警告。
记录(record)类型
C#中的
==
运算符默认是判断两个变量指向的是否是同一个对象,即使两个对象内容完全一样,也不相等。可以通过重写Equals方法、重写==
运算符等来解决这个问题,不过需要开发人员编写非常多的额外代码。
从C#9开始,加了记录(record)类型的语法,编译器会为我们自动生成Equals、GetHashcode等方法。
Person.cs
public record Person(string FirstName, string LastName);
Person p1 = new Person("Yang", "Zack");
Person p2 = new Person("Yang","Zack");
Person p3 = new Person("Gates", "Bill");
Console.WriteLine(p1);
Console.WriteLine(p1==p2);
Console.WriteLine(p1==p3);
Console.WriteLine(p1.FirstName);
/*
输出结果:
Person { FirstName = Yang, LastName = Zack }
True
False
Yang
*/
编译器会根据Person类型中的属性定义,自动为Person类型生成包含全部属性的构造方法。注意,默认情况下,编译器会生成一个包含所有属性的构造方法,因此,我们编写new Person()、new Person(“Yang”)这两种写法都是不可以的。也会生成ToString方法和Equals等方法。
可以实现部分属性是只读的、而部分属性是可以读写。
public record Person(string FirstName, string LastName)
{
public int Age { get; set; }
}
Person p1 = new Person("Yang", "Zack");
p1.Age = 10;
默认生成的构造方法的行为不能修改,我们可以为类型提供多个构造方法,然后其他构造方法通过this调用默认的构造方法。
public record Person(string FirstName, string LastName)
{
public int Age { get; set; }
public Person(string FirstName, string LastName, int age): this(FirstName, LastName)
{
this.Age = age;
}
}
实例化:
Person p4 = new Person("Yang", "Kang", 10);
用with关键字生成一个对象的副本
Person p1 = new Person("Yang", "Kang", 10);
Person p2 = p1 with { }; //生成的是一个属性相同,引用地址不同的全新对象
Console.WriteLine(p1 == p2);
//比较两个对象的引用地址是否相等
Console.WriteLine(object.ReferenceEquals(p1, p2));
Person p3 = p1 with { Age = 18}; //指定Age的值,别的属性值相同
Console.WriteLine(p3);
/*
输出结果:
True
False
Person { FirstName = Yang, LastName = Kang, Age = 18 }
*/