.net Core重难点知识
C#新语法
顶级语句
之前必须有类和类中的Main方法,从C#9.0开始,可以直接在C#文件中编写入口代码,不需要再声明类和方法
//之前的方法
internalclassProgram
{
staticvoidMain(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
//顶级语句
Console.WriteLine("Hello, World!");
一个项目中只能有一个文件具有顶级语句
全局using指令
有些类库在多个文件中都会引用,使用全局using指令可以只写一遍则项目中所有的源码都可以使用了,通常将全局using指令单独写一个C#文件。
globalusingMircrosoft.Data.Sqlite;
globalusingSystem.Text.Json;
另外,在csproj文件中加入<ImplicitUsings>enable</ImplicitUsings>
编译器会根据项目类型自动隐式加上System等常用明明空间的引入。
using声明
//旧的using释放资源,里面有多重嵌套
using (varconn=newSqlConnection(connStr))
{
conn.Open();
using (varcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_Articles";
using (SqlDataReaderreader=cmd.ExecuteReader())
{
while (reader.Read())
{
}
}
}
}
C#8以后,可以使用using声明如果类型实现了IDisposable或者IAsyncDisposable接口,则当代码离开using声明的变量作用域的时候,自动调用Dispose方法。
usingSystem.Data.SqlClient;
stringconnStr="Data Source=.;Initial Catalog=demo1;Integrated Security=True";
usingvarconn=newSqlConnection(connStr);
conn.Open();
usingvarcmd=conn.CreateCommand();
cmd.CommandText="select * from T_Articles";
usingvarreader=cmd.ExecuteReader();
while (reader.Read())
{
}
要注意使用的时机
//以下是有问题的代码
/*
using var outStream = File.OpenWrite("e:/1.txt");
using var writer = new StreamWriter(outStream);
writer.WriteLine("hello");
string s = File.ReadAllText("e:/1.txt"); //这句会报错,因为此时1.txt仍然被outStream占用
Console.WriteLine(s);*/
{
usingvaroutStream=File.OpenWrite("e:/1.txt");
usingvarwriter=newStreamWriter(outStream);
writer.WriteLine("hello");
}
strings=File.ReadAllText("e:/1.txt");
Console.WriteLine(s);
简化命名空间声明
之前版本,类必须在命名空间中
namespaceConsoleApp2
{
classProgram
{
}
}
在C#10之后,可以不再使用{},文件中所有的类型都是这个命名空间下的成员
namespaceTMS.Admin;
classTeacher
{
publicintId { get; set; }
publicstringName { get; set; }
}
可空类型
在引用类型后面加上?表示该变量是可以为null
在使用该变量后,vs会给出警告“解引用可能出现空引用”
如果确定变量不会为空,则可以使用!抑制编译器的警告person.number!.ToLower()
,但是尽量少用
记录类型
如果两个对象为同一类型,并且属性完全相等,但是他们为不同的对象,使用==比较的话会返回false,可以通过重写Equals、==等来解决,但是比较麻烦。
C#9.0新增记录(record)类型,自动生成Equals,GetHashcode,ToString等方法。
public record Person(string FirstName, string LastName);
编译器会根据Person中的属性定义(括号中),自动生成包含全部属性的构造方法。此时使用new Person()/new Person("张三")
是错误的,但是所有的属性是只读的。
Personp1=newPerson("Zack", "Yang");
Personp2=newPerson("Zack", "Yang");
Console.WriteLine(p1);//Person { FirstName = Zack, LastName = Yang }
Console.WriteLine(p1==p2);// true 此时比较的是两个对象的属性值
定义部分属性可读可写
publicrecordPerson(stringLastName)
{
publicstringFirstName { get; set; }
publicvoidSayHello()
{
Console.WriteLine($"Hello,我是{LastName} {FirstName}");
}
}
此时LastName仍然是自动生成的可读属性。新建实例:Person s = new Person("y")
提供多个构造函数
publicrecordUser(stringUserName, string?Email, intAge)
{
publicUser(stringuserName, intage)
: this(userName, null, age){ }
}
- 编译器会自动生成包含这3个属性的构造方法
- 自己可以自定义其他的构造方法
总结:recode总是默认生成包含全部属性的构造函数,且属性是只读的
创建副本
Useru1=newUser("a","b",19);
Useru2=newUser(u1.userName,"c",20);//可以使用这种方法
Useru3=u1with(Email="test@qq.com");//推荐