C#新特性
https://blog.csdn.net/u012094427/article/details/77201025
https://www.cnblogs.com/shiyh/p/8884677.html
4.0 VS2010 .Net 4.0
System.Threading.Tasks.Task
Task对象是.Net Framework 4.0之后出现的异步编程的一个重要对象。在一定程度上来说,Task对象可以理解Thread对象的一个升级产品。既然是升级产品,那它肯定有他的优势,比如我们上面Thread对象不能解决的问题:对于有返回值类型的委托。Task对象就能简单的解决。
//用法一
Task task1 = new Task(new Action(MyAction));
//用法二
Task task2 = new Task(delegate { MyAction(); });
//用法三
Task task3 = new Task(() => MyAction());
//用法四
Task task4 = new Task(() => { MyAction(); });
task1.Start();
task2.Start();
task3.Start();
task4.Start();
var strRes = Task.Run<string>(() => { return GetReturnResult(); });//启动Task执行方法
Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
Console.WriteLine(strRes.Result);//得到方法的返回值
5.0 VS2012 .Net 4.5
async和await
APM
C# .NET最早出现的异步编程模式被称为APM(Asynchronous Programming Model)。这种模式主要由一对Begin/End开头的组成。
EAP
在C#.NET第二个版本中,增加了一种新的异步编程模型EAP(Event-based Asynchronous Pattern),EAP模式的异步代码中,典型特征是一个Async结尾的方法和Completed结尾的事件。
在.Net 4.5中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型TAP(Task-based Asynchronous Pattern)。在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型。类中存在TaskAsync为后缀的方法时就代表该类实现了TAP, 并且基于任务的异步模式同样也支持异步操作的取消和进度的报告的功能,但是这两个实现都不像EAP中实现的那么复杂,因为如果我们要自己实现EAP的类,我们需要定义多个事件和事件处理程序的委托类型和事件的参数(具体可以查看上一专题中的BackgroundWorker剖析部分),但是在TAP实现中,我们只需要通过向异步方法传入CancellationToken 参数,因为在异步方法内部会对这个参数的IsCancellationRequested属性进行监控,当异步方法收到一个取消请求时,异步方法将会退出执行(具体这点可以使用反射工具查看WebClient的DownloadDataTaskAsync方法,同时也可以参考我后面部分自己实现基于任务的异步模式的异步方法。),在TAP中,我们可以通过IProgress<T>接口来实现进度报告的功能,
static async Task TestAsync()
{
Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
var name = GetReturnResult();
Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", await name, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
}
await name 等价于 name.GetAwaiter().GetResult()
绑定运算符,:=:
comboBox1.Text :=: textBox1.Text;
带参数的泛型构造函数
public class T MyClass : T: class, new()
public class T MyClass : T:class, new(int)
支持null类型运算
int x? = null;
int y? = x + 40;
Myobject obj = null;
Myotherobj obj2 = obj.MyProperty ??? new Myotherobj();
case支持表达式
switch(myobj){
llorEmpty(myotherobj):
//逻辑代码
case myotherobj.Trim().Lower:
//逻辑代码
}
扩展属性
我们在C#3.0里有扩展方法,那么在C#5.0里将会加入扩展属性的感念,对照扩展方法,不难理解扩展属性的概念了。以下为扩展属性的定义举例:
[Associate(string)]
public static int Zivsoft_ExtensionProperty { get;set;}
在lambdas中使用循环变量
在C#之前的版本中,如果你编写了一个循环,你不能在lambda中使用循环变量。事实上,它比想象中更糟。你可以在lambda中使用循环变量,但是它将给你一个错误的结果。它会使用循环退出时的变量值,不是被捕获时的值。
public static List<Func<int, int>> GetAdders(params int[] addends) {
var funcs = new List<Func<int, int>>();
foreach (int addend in addends) {
funcs.Add(i => i + addend);
}
return funcs;
}
6.0 VS2015 .Net 4.6
自动的属性初始化器Auto Property initialzier
public class AutoPropertyInCsharp6
{
public long PostID { get; } = 1;
public string PostName { get; } = "Post 1";
public string PostTitle { get; protected set; } = string.Empty;
}
字典初始化器
public class DictionaryInitializerInCSharp6
{
public Dictionary<string, string> _users { get; } = new Dictionary<string, string>()
{
[
using System.Console;
catch块里面的await
C# 6 之前catch和finally块中是不能用 await 关键词的. 在 C# 6 中,我们终于可以再这两个地方使用await了.
异常过滤器
异常过滤器可以让你在catch块执行之前先进行一个 if 条件判断.
看看这个发生了一个异常的示例,现在我们想要先判断里面的Exception是否为null,然后再执行catch块
try
{
//Some code
}
catch (Exception ex) if (ex.InnerException == null)
{
//Do work
}
用于检查NULL值的条件访问操作符?
var userRank = UserID?.Rank ?? "No Rank";
int? a = ObjA?.Count;
ClassA objA = CollectionA?[0];
7.0 VS2017 .Net 4.7
输出变量
在当前的 C# 中,使用输出参数并不像我们想的那样方便。在你调用一个无输出参数的方法之前,首先必须声明一个变量并传递给它。如果你没有初始化这些变量,你就无法使用 var 来声明它们,除非先指定完整的类型
C#7.0 中,我们正在增加输出变量和声明一个作为能够被传递的输出实参的变量的能力:
public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out int y);
WriteLine($"({x}, {y})");
}
模式匹配
在 C#7.0,我们正在加强两个现有的具有模式的语言结构:
- is 表达式现在具有一种右手侧的模式,而不仅仅是一种类型
- switch 语句中的 case 语句现在可以使用匹配模式,不只是常数值
具有模式的 IS 表达式
下面是使用 is 表达式的示例,其中利用了常量模式和类型模式:
public void PrintStars(object o)
{
if (o is null) return; // constant pattern "null"
if (!(o is int i)) return; // type pattern "int i"
WriteLine(new string('*', i));
}
模式和 Try方法可以很好地协同:
if (o is int i || (o is string s && int.TryParse(s, out i)) { /* use i */ }
具有模式的 Switch 语句
我们正在归纳 Switch 语句:
- 可以设定任何类型的 Switch 语句(不只是原始类型)
- 模式可以用在 case 语句中
- Case 语句可以有特殊的条件
下面是一个简单的例子:
switch(shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("<unknown shape>");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
元组
这是一个从方法中返回多个值的常见模式。目前可选用的选项并非是最佳的:
- 输出参数:使用起来比较笨拙(即使有上述的改进),他们在使用异步方法是不起作用的。
- System.Tuple<...> 返回类型:冗余使用和请求一个元组对象的分配。
- 方法的定制传输类型:对于类型,具有大量的代码开销,其目的只是暂时将一些值组合起来。
- 通过动态返回类型返回匿名类型:很高的性能开销,没有静态类型检查。
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
局部函数
有时候,一个辅助函数可以在一个独立函数内部起作用。现在,你可以以一个局部函数的方式在其它函数内部声明这样的函数:
public int Fibonacci(int x)
{
if (x < 0) throw new ArgumentException("Less negativity please!", nameof(x));
return Fib(x).current;
(int current, int previous) Fib(int i)
{
if (i == 0) return (1, 0);
var (p, pp) = Fib(i - 1);
return (p + pp, p);
}
}
文字改进
C#7.0 允许 _ 出现,作为数字分隔号:
var d = 123_456;
引用返回和局部引用
引用返回和局部引用
就像在 C# 中通过引用来传递参数(使用引用修改器),你现在也可以通过引用来返回参数,同样也可以以局部变量的方式存储参数。
public ref int Find(int number, int[] numbers)
{
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == number)
{
return ref numbers[i]; // return the storage location, not the value
}
}
throw new IndexOutOfRangeException($"{nameof(number)} not found");
}
int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // aliases 7's place in the array
place = 9; // replaces 7 with 9 in the array
WriteLine(array[4]); // prints 9
Throw 表达式
在表达式中间抛出一个异常是很容易的:只需为自己的代码调用一个方法!但在 C#7.0 中,我们允许在任意地方抛出一个表达式:
class Person
{
public string Name { get; }
public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
public string GetFirstName()
{
var parts = Name.Split(" ");
return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
}
public string GetLastName() => throw new NotImplementedException();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)