一、类型发展
C#1中是没有泛型的 在C#2中在逐渐推出泛型。C#2还引入了可空类型。
1 C#3:引入了匿名类型、和隐式的局部变量(var)
匿名类型:我们主要是使用在LINQ查询语句。就算没有LINQ查询语句我们在一种类型只在一个方法中,我们创建数据类型供单一方法的使用,的这种方式也不可取。不过需要注意匿名类型的作用域只在声明的局部作用域中能使用。
2 C#7中可以采用Readonly Struct 自定义结构
举个例子:
cs
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
cs
Point p1 = new Point(2, 3);
Console.WriteLine($"p1: ({p1.X}, {p1.Y})");
// 尝试修改结构的属性值,将会引发编译错误
// p1.X = 5;
// p1.Y = 10;
Point p2 = new Point(5, 10);
Console.WriteLine($"p2: ({p2.X}, {p2.Y})");
// 结构的属性值无法修改,因此下面的赋值操作是创建了一个新的Point实例
Point p3 = p2;
Console.WriteLine($"p3: ({p3.X}, {p3.Y})");
示例解释:
上述代码中,我们创建了一个Point对象,打印了它的坐标,并尝试修改它的属性值。由于Point是不可变的结构,所以修改属性值的操作会导致编译错误。然后,我们创建了另一个Point对象p2,并将其赋值给p3。由于结构是不可变的,所以赋值操作实际上是创建了一个新的Point实例。
3 C#7中引入了元组:
元组可以替代我们前面提到的匿名类型。其中不同的是元组可以用于方法的返回类型,和参数。建议放在内部的API中不对外暴露。因为元组只是对简单的值组合进行一个赋值。并没有对其封装。
举个例子:
你可以使用如下的语法来创建一个元组:
cs
var myTuple = (value1, value2, value3);
你还可以给元组的成员命名,以增加代码的清晰度:
cs
var myNamedTuple = (Name: "John", Age: 30, City: "New York");
也可创建匿名类型 任何类型都可以创建
怎么使用?
cs
var myTuple = (45, 88, 99);
Console.WriteLine(myTuple.Item1);//代表第一个元素 结果 45
如果您给元组的成员命名了 那么就可以使用名称来输出
cs
var myNamedTuple = (Name: "John", Age: new { maximum = "100", minimum = "10" }, City: "New York");
Console.WriteLine(myNamedTuple.Name);
当需要访问元组的成员时,你可以使用点符号或者解构语法来拆包:
cs
var myNamedTuple = (Name: "John", Age: new { maximum = "100", minimum = "10" }, City: "New York");
Console.WriteLine(myNamedTuple.Name);
var (name, age, city) = myNamedTuple;
Console.WriteLine(name);
Console.WriteLine(age.maximum); // 访问嵌套匿名类型的属性
Console.WriteLine(city);
下面是一个示例,展示了如何在方法的返回类型和参数中使用元组:
cs
public static (int, string) GetPerson()
{
int age = 25;
string name = "John Doe";
return (age, name);
}
public static void PrintPerson((int, string) person)
{
Console.WriteLine("Name: " + person.Item2);
Console.WriteLine("Age: " + person.Item1);
}
// 使用示例
var person = GetPerson();
PrintPerson(person);
C#8中引入了可空引用类型:C#8假设没有使用任何显示声明的返回值、参数、属性、全局或局部变量都是默认为为空类型的。
二、代码更简洁
1 C#1中,需要先写一个委托可以指向方法,然后再写一大段代码来创建委托。
举个例子:
cs
class Myeven
{
public delegate void MyAction(object sender, ElapsedEventArgs e);
public event MyAction myeven;
Timer Timer;
public Myeven()
{
Timer ??= new Timer();
Timer.Elapsed += new ElapsedEventHandler(DLonti);
}
private void DLonti(object sender, ElapsedEventArgs e)
{
}
}
2 C#2引入方法组转换和匿名方法后就可以采用以下形式,匿名方法没有参数列表则可以忽略
cs
class Myeven
{
public delegate void MyAction(object sender, ElapsedEventArgs e);
public event MyAction myeven;
Timer Timer;
public Myeven()
{
Timer ??= new Timer();
Timer.Elapsed += delegate (object L, ElapsedEventArgs elapsedEventArgs)
{
//方法体
};
}
}
提示:在匿名方法当中您必须显示指定参数类型。
3 C#3推出Lambda表达式几乎具备了匿名函数的所有优点而且它的语法更简洁
cs
class Myeven
{
public delegate void MyAction(object sender, ElapsedEventArgs e);
public event MyAction myeven;
Timer Timer;
public Myeven()
{
Timer ??= new Timer();
Timer.Elapsed += (obj, e) => { //隐式声明参数列表
//方法体
};
//Timer.Elapsed += (object obj, ElapsedEventArgs e) => {//显示声明参数列表
// //方法体
//};
}
}
4 C#3引入了对象初始化和集合初始化。
5 C#3推出了自动属性
举个例子:
cs
class Myeven
{
//自动属性 C#3中引人的
public int MyProperty { get; set; }
private int myVar;
//传统属性
public int MyProperty2
{
get { return myVar; }
set { myVar = value; }
}
}
6 C#6引入了表达式主体成员
在上面的示例中,我们可以将 MyProperty2
属性改写为使用表达式主体成员的形式,
如下所示:
cs
public int MyProperty2
{
get => myVar;
set => myVar = value;
}
示例解释:
我们使用
=>
箭头运算符来定义属性的读取和写入逻辑。对于get
访问器,我们直接返回myVar
字段的值;对于set
访问器,我们将属性的值赋给myVar
字段。
三、字符串处理
1 C#4引用了动态类型
2 C#5引入了调用方法信息特性
举个例子:
cs
using System;
using System.Runtime.CompilerServices;
public class Program
{
public static void Main(string[] args)
{
LogMessage("Hello, world!");
}
public static void LogMessage(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string memberName = "")
{
Console.WriteLine($"Message: {message}");
Console.WriteLine($"File Path: {filePath}");
Console.WriteLine($"Line Number: {lineNumber}");
Console.WriteLine($"Member Name: {memberName}");
}
}
示例解释:
在上面的示例中,我们定义了一个名为
LogMessage
的方法,并将其标记为使用了 "调用方信息特性"。在LogMessage
方法的参数中,我们使用了CallerFilePath
、CallerLineNumber
和CallerMemberName
属性。这些属性会自动获取调用方的文件路径、行号和成员名称。在
Main
方法中调用LogMessage
方法时,会将参数传递给LogMessage
。当执行到LogMessage
方法时,你将看到输出的结果如下:
输出结果:
3 C#6引入了nameof 运算符用于获取变量类型方法和成员的名字
举个例子:
cs
class Myeven:INotifyPropertyChanged
{
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(myVar))); }//nameof(myVar)替代原来的 "myVar"
}
public event PropertyChangedEventHandler PropertyChanged;
}
4 C#6引入了内插字符串字面量
举个例子:
cs
class Myeven
{
private int name;
public int Name
{
get { return name; }
set { name = value; }
}
public Myeven()
{
Console.WriteLine("姓名"+Name);
Console.WriteLine($"姓名{Name}");
}
}
只是部分内容分享其实还有很多我没有提及到