石家庄 网站建站,校园二手网站的建设方案,宣城市建设监督管理局网站下载,wordpress设置先登录再进入代码演示C#各版本新功能C#各版本新功能其实都能在官网搜到#xff0c;但很少有人整理在一起#xff0c;并通过非常简短的代码将每个新特性演示出来。代码演示C#各版本新功能C# 2.0版 - 2005泛型分部类型匿名方法可以为null的值类型迭代器协变和逆变C# 3.0版 - 2007自动实现的… 代码演示C#各版本新功能C#各版本新功能其实都能在官网搜到但很少有人整理在一起并通过非常简短的代码将每个新特性演示出来。代码演示C#各版本新功能C# 2.0版 - 2005泛型分部类型匿名方法可以为null的值类型迭代器协变和逆变C# 3.0版 - 2007自动实现的属性匿名类型查询表达式LINQLambda表达式表达式树扩展方法var分部方法对象和集合初始值设定项C# 4.0版 - 2010dynamic命名参数/可选参数泛型中的协变和逆变类型等效、内置互操作类型C# 5.0版 - 2012async/await调用方信息C# 6.0版 - 2015静态导入异常筛选器自动初始化表达式Expression-bodied 函数成员Null传播器字符串内插nameof表达式索引初始值设定项C# 7.0版本 - 2017out变量元组和析构函数模式匹配本地函数更多的expression-bodied成员Ref 局部变量和返回结果弃元二进制文本和数字分隔符throw表达式C# 8.0 版 - 2019Readonly 成员默认接口方法模式匹配增强属性模式Tuple模式位置模式switch表达式using声明静态本地函数异步流索引和范围Null合并赋值非托管构造类型嵌套表达式中的 stackalloc附录/总结C# 2.0版 - 2005泛型Java中的泛型不支持值类型且会运行时类型擦除这一点 .NET更优秀。// Declare the generic class.
public class GenericListT
{public void Add(T input) { }
}
class TestGenericList
{private class ExampleClass { }static void Main(){// Declare a list of type int.GenericListint list1 new GenericListint();list1.Add(1);// Declare a list of type string.GenericListstring list2 new GenericListstring();list2.Add();// Declare a list of type ExampleClass.GenericListExampleClass list3 new GenericListExampleClass();list3.Add(new ExampleClass());}
}
分部类型拆分一个类、一个结构、一个接口或一个方法的定义到两个或更多的文件中是可能的。每个源文件包含类型或方法定义的一部分编译应用程序时将把所有部分组合起来。public partial class Employee
{public void DoWork(){}
}
public partial class Employee
{public void GoToLunch(){}
}
匿名方法Funcint, int, int sum delegate (int a, int b) { return a b; };
Console.WriteLine(sum(3, 4)); // output: 7
可以为null的值类型double? pi 3.14;
char? letter a;
int m2 10;
int? m m2;
bool? flag null;
// An array of a nullable type:
int?[] arr new int?[10];
迭代器static void Main()
{foreach (int number in SomeNumbers()){Console.Write(number.ToString() );}// Output: 3 5 8Console.ReadKey();
}
public static System.Collections.IEnumerable SomeNumbers()
{yield return 3;yield return 5;yield return 8;
}
协变和逆变在 C# 中协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。协变保留分配兼容性逆变则与之相反。// Assignment compatibility.
string str test;
// An object of a more derived type is assigned to an object of a less derived type.
object obj str;
// Covariance.
IEnumerablestring strings new Liststring();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerableobject objects strings;
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Actionobject actObject SetObject;
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Actionstring actString actObject;
C# 3.0版 - 2007自动实现的属性// This class is mutable. Its data can be modified from
// outside the class.
class Customer
{// Auto-implemented properties for trivial get and setpublic double TotalPurchases { get; set; }public string Name { get; set; }public int CustomerID { get; set; }// Constructorpublic Customer(double purchases, string name, int ID){TotalPurchases purchases;Name name;CustomerID ID;}// Methodspublic string GetContactInfo() { return ContactInfo; }public string GetTransactionHistory() { return History; }// .. Additional methods, events, etc.
}
class Program
{static void Main(){// Intialize a new object.Customer cust1 new Customer(4987.63, Northwind, 90108);// Modify a property.cust1.TotalPurchases 499.99;}
}
匿名类型var v new { Amount 108, Message Hello };
// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and n .
Console.WriteLine(v.Amount v.Message);
查询表达式LINQLINQ允许你可以像写 SQL一样写 C#代码像这样from p in persons
where p.Age 18 p.IsBeatiful
select new
{p.WeChatId, p.PhoneNumber
}
LINQ的意义在于让 C#做出了重大调整本章中说到的 lambda表达式、扩展方法、表达式树、匿名类型、自动属性等都是 LINQ的必要组成部分。由于用扩展方法的形式也能得到一致的结果而且还能让代码风格更加一致所以我平时用 LINQ语法较少// 与上文代码相同但改成了扩展方法风格
persons.Where(x x.Age 18 x.IsBeatiful).Select(x new {x.WeChatId, x.PhoneNumber, });
Lambda表达式Funcint, int square x x * x;
Console.WriteLine(square(5));
// Output:
// 25
表达式树这个是 LINQ的基础之一它的作用是将代码像数据一样保存在内存中然后稍后对这些“代码数据”进行重新解释/执行。EntityFramework就是一个经典场景它先将表达式树保存起来然后执行时将其翻译为 SQL发给数据库执行。注意表达式树并不能表示所有的代码 C# 3.0之后的语法包含 ??、 ?.、 asyncawait、可选参数等都无法放到表达式树中。据说官方准备更新它但迟迟没有进展。扩展方法扩展方法使你能够向现有类型“添加”方法而无需创建新的派生类型、重新编译或以其他方式修改原始类型。static void Main()
{Console.WriteLine (Perth.IsCapitalized()); // Equivalent to:Console.WriteLine (StringHelper.IsCapitalized (Perth)); // Interfaces can be extended, too:Console.WriteLine (Seattle.First()); // S
}
public static class StringHelper
{public static bool IsCapitalized (this string s){if (string.IsNullOrEmpty(s)) return false;return char.IsUpper (s[0]);}public static T FirstT (this IEnumerableT sequence){foreach (T element in sequence)return element;throw new InvalidOperationException (No elements!);}
}
varvar i 10; // Implicitly typed.
int i 10; // Explicitly typed.
分部方法namespace PM
{partial class A{partial void OnSomethingHappened(string s);}// This part can be in a separate file.partial class A{// Comment out this method and the program// will still compile.partial void OnSomethingHappened(String s){Console.WriteLine(Something happened: {0}, s);}}
}
对象和集合初始值设定项public class Cat
{// Auto-implemented properties.public int Age { get; set; }public string Name { get; set; }public Cat(){}public Cat(string name){this.Name name;}
}
C# 4.0版 - 2010dynamic这个是特性使得 CLR不得不进行一次修改。有了这个 C#也能像 js、 php、 python等弱类型语言一样写代码了。dynamic a 3;
a 3.14;
a Hello World;
a new[] { 1, 2, 3, 4, 5 };
a new Funcint(() 3);
a new StringBuilder();
Console.WriteLine(a.GetType().Name); // StringBuilder
注意 dynamic可以表示任何东西包含数组、委托等等。滥用 dynamic容易让程序变得很难维护。命名参数/可选参数PrintOrderDetails(productName: Red Mug, sellerName: Gift Shop, orderNum: 31);
public void ExampleMethod(int required, string optionalstr default string,int optionalint 10)
泛型中的协变和逆变IEnumerableDerived d new ListDerived();
IEnumerableBase b d;
ActionBase b (target) { Console.WriteLine(target.GetType().Name); };
ActionDerived d b;
d(new Derived());
类型等效、内置互操作类型这个主要是为了和 COM进行交互。之前需要引用一些 COM类型相关的程序集现在可以直接引用 COM。具体可以参见https://docs.microsoft.com/zh-cn/dotnet/framework/interop/type-equivalence-and-embedded-interop-typesC# 5.0版 - 2012async/awaitprivate DamageResult CalculateDamageDone()
{// Code omitted://// Does an expensive calculation and returns// the result of that calculation.
}
calculateButton.Clicked async (o, e)
{// This line will yield control to the UI while CalculateDamageDone()// performs its work. The UI thread is free to perform other work.var damageResult await Task.Run(() CalculateDamageDone());DisplayDamage(damageResult);
};
async/ await的本质是状态机像 IEnumerableT一样。以前游戏引擎 Unity只支持 C# 3.0因此当时它用状态机发 Http请求是用的 IEnumerableT。async/ await有两个好处一是可以避免 UI线程卡顿二是提高系统吞吐率最终提高性能。调用方信息public void DoProcessing()
{TraceMessage(Something happened.);
}
public void TraceMessage(string message,[CallerMemberName] string memberName ,[CallerFilePath] string sourceFilePath ,[CallerLineNumber] int sourceLineNumber 0)
{System.Diagnostics.Trace.WriteLine(message: message);System.Diagnostics.Trace.WriteLine(member name: memberName);System.Diagnostics.Trace.WriteLine(source file path: sourceFilePath);System.Diagnostics.Trace.WriteLine(source line number: sourceLineNumber);
}
// Sample Output:
// message: Something happened.
// member name: DoProcessing
// source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31
注意这个是编译期生成的因此比 StackTrace更能保证性能。C# 6.0版 - 2015静态导入终于可以不用写静态类名了。using static System.Math;
using static System.Console;
WriteLine(Sin(3.14)); // 0.00159265291648683
异常筛选器在 try-catch时可以按指定的条件进行 catch其它条件不 catch。public static async Taskstring MakeRequest()
{WebRequestHandler webRequestHandler new WebRequestHandler();webRequestHandler.AllowAutoRedirect false;using (HttpClient client new HttpClient(webRequestHandler)){var stringTask client.GetStringAsync(https://docs.microsoft.com/en-us/dotnet/about/);try{var responseText await stringTask;return responseText;}catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains(301)){return Site Moved;}}
}
自动初始化表达式public ICollectiondouble Grades { get; } new Listdouble();
Expression-bodied 函数成员public override string ToString() ${LastName}, {FirstName};
Null传播器var first person?.FirstName;
字符串内插public string GetGradePointPercentage() $Name: {LastName}, {FirstName}. G.P.A: {Grades.Average():F2};
nameof表达式有时字符串值和某个变量名称一致尤其是在做参数验证时。这里 nameof就能在编译期自动从变量名生成一个字符串。if (IsNullOrWhiteSpace(lastName))throw new ArgumentException(message: Cannot be blank, paramName: nameof(lastName));
索引初始值设定项使集合初始化更容易的另一个功能是对 Add 方法使用扩展方法 。添加此功能的目的是进行 Visual Basic 的奇偶校验。如果自定义集合类的方法具有通过语义方式添加新项的名称则此功能非常有用。C# 7.0版本 - 2017out变量if (int.TryParse(input, out int result))Console.WriteLine(result);
elseConsole.WriteLine(Could not parse input);
元组和解构函数(string Alpha, string Beta) namedLetters (a, b);
Console.WriteLine(${namedLetters.Alpha}, {namedLetters.Beta});
解构是将元组转换为变量。//忽略…构函数应该类似C中的析构函数在实例回收时执行模式匹配现在可以在匹配一个类型时自动转换为这个类型的变量如果转换失败这个变量就赋值为默认值 null或 0。极简版if (input is int count)sum count;
switch/case版public static int SumPositiveNumbers(IEnumerableobject sequence)
{int sum 0;foreach (var i in sequence){switch (i){case 0:break;case IEnumerableint childSequence:{foreach(var item in childSequence)sum (item 0) ? item : 0;break;}case int n when n 0:sum n;break;case null:throw new NullReferenceException(Null found in sequence);default:throw new InvalidOperationException(Unrecognized type);}}return sum;
}
本地函数这个主要是方便 javascript就能这样写。比 lambda的好处在于这个可以定义在后面而 lambda必须定义在前面。public static IEnumerablechar AlphabetSubset3(char start, char end)
{if (start a || start z)throw new ArgumentOutOfRangeException(paramName: nameof(start), message: start must be a letter);if (end a || end z)throw new ArgumentOutOfRangeException(paramName: nameof(end), message: end must be a letter);if (end start)throw new ArgumentException(${nameof(end)} must be greater than {nameof(start)});return alphabetSubsetImplementation();IEnumerablechar alphabetSubsetImplementation(){for (var c start; c end; c)yield return c;}
}
更多的expression-bodied成员该功能可以让一些函数写成表达式的形式非常的方便。// Expression-bodied constructor
public ExpressionMembersExample(string label) this.Label label;
// Expression-bodied finalizer
~ExpressionMembersExample() Console.Error.WriteLine(Finalized!);
private string label;
// Expression-bodied get / set accessors.
public string Label
{get label;set this.label value ?? Default label;
}
Ref 局部变量和返回结果此功能允许使用并返回对变量的引用的算法这些变量在其他位置定义。一个示例是使用大型矩阵并查找具有某些特征的单个位置。这个功能主要是为了提高值类型的性能让它真正发挥其作用。 C就有类似的功能。public static ref int Find(int[,] matrix, Funcint, bool predicate)
{for (int i 0; i matrix.GetLength(0); i)for (int j 0; j matrix.GetLength(1); j)if (predicate(matrix[i, j]))return ref matrix[i, j];throw new InvalidOperationException(Not found);
}
ref var item ref MatrixSearch.Find(matrix, (val) val 42);
Console.WriteLine(item);
item 24;
Console.WriteLine(matrix[4, 2]);
弃元通常在进行元组解构或使用 out参数调用方法时必须定义一个其值无关紧要且你不打算使用的变量。为处理此情况 C#增添了对弃元的支持 。弃元是一个名为 _的只写变量可向单个变量赋予要放弃的所有值。弃元类似于未赋值的变量不可在代码中使用弃元赋值语句除外。using System;
using System.Collections.Generic;
public class Example
{public static void Main(){var (_, _, _, pop1, _, pop2) QueryCityDataForYears(New York City, 1960, 2010);Console.WriteLine($Population change, 1960 to 2010: {pop2 - pop1:N0});}private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2){int population1 0, population2 0;double area 0;if (name New York City){area 468.48; if (year1 1960){population1 7781984;}if (year2 2010){population2 8175133;}return (name, area, year1, population1, year2, population2);}return (, 0, 0, 0, 0, 0);}
}
// The example displays the following output:
// Population change, 1960 to 2010: 393,149
二进制文本和数字分隔符这个用于使数字和二进制更可读。// 二进制文本
public const int Sixteen 0b0001_0000;
public const int ThirtyTwo 0b0010_0000;
public const int SixtyFour 0b0100_0000;
public const int OneHundredTwentyEight 0b1000_0000;
// 数字分隔符
public const long BillionsAndBillions 100_000_000_000;
public const double AvogadroConstant 6.022_140_857_747_474e23;
public const decimal GoldenRatio 1.618_033_988_749_894_848_204_586_834_365_638_117_720_309_179M;
throw表达式throw之前必须是一个语句因此有时不得不写更多的代码来完成所需功能。但 7.0提供了 throw表达式来使代码更简洁阅读更轻松。void Main()
{// You can now throw expressions in expressions clauses.// This is useful in conditional expressions:string result new Random().Next(2) 0 ? Good : throw new Exception (Bad);result.Dump();Foo().Dump();
}
public string Foo() throw new NotImplementedException();
C# 8.0 版 - 2019Readonly 成员public readonly override string ToString() $({X}, {Y}) is {Distance} from the origin;
默认接口方法接口中也能定义方法了这个新功能经常受到争论。但想想有时是先定义接口而实现接口需要实现很多相关、但又繁琐的功能如 ASP.NETCore中的 ILogger谁用谁知道特别多需要实现的方法但又都差不多。因此所以这个功能其实很有必要。void Main()
{ILogger foo new Logger();foo.Log (new Exception (test));
}
class Logger : ILogger
{ public void Log (string message) Console.WriteLine (message);
}
interface ILogger
{void Log (string message); // Adding a new member to an interface need not break implementors:public void Log (Exception ex) Log (ExceptionHeader ex.Message);// The static modifier (and other modifiers) are now allowed:static string ExceptionHeader Exception: ;
}
模式匹配增强这个是为简化代码、函数式编程而生的我个人非常喜欢。属性模式public static decimal ComputeSalesTax(Address location, decimal salePrice) location switch{{ State: WA } salePrice * 0.06M,{ State: MN } salePrice * 0.75M,{ State: MI } salePrice * 0.05M,// other cases removed for brevity..._ 0M};
Tuple模式public static string RockPaperScissors(string first, string second) (first, second) switch{(rock, paper) rock is covered by paper. Paper wins.,(rock, scissors) rock breaks scissors. Rock wins.,(paper, rock) paper covers rock. Paper wins.,(paper, scissors) paper is cut by scissors. Scissors wins.,(scissors, rock) scissors is broken by rock. Rock wins.,(scissors, paper) scissors cuts paper. Scissors wins.,(_, _) tie};
位置模式static Quadrant GetQuadrant(Point point) point switch
{(0, 0) Quadrant.Origin,var (x, y) when x 0 y 0 Quadrant.One,var (x, y) when x 0 y 0 Quadrant.Two,var (x, y) when x 0 y 0 Quadrant.Three,var (x, y) when x 0 y 0 Quadrant.Four,var (_, _) Quadrant.OnBorder,_ Quadrant.Unknown
};
switch表达式这个功能能使代码从大量的 if/else或 switch/case变成“一行代码”符合函数式编程的思想非常好用public static RGBColor FromRainbow(Rainbow colorBand) colorBand switch{Rainbow.Red new RGBColor(0xFF, 0x00, 0x00),Rainbow.Orange new RGBColor(0xFF, 0x7F, 0x00),Rainbow.Yellow new RGBColor(0xFF, 0xFF, 0x00),Rainbow.Green new RGBColor(0x00, 0xFF, 0x00),Rainbow.Blue new RGBColor(0x00, 0x00, 0xFF),Rainbow.Indigo new RGBColor(0x4B, 0x00, 0x82),Rainbow.Violet new RGBColor(0x94, 0x00, 0xD3),_ throw new ArgumentException(message: invalid enum value, paramName: nameof(colorBand)),};
using声明static int WriteLinesToFile(IEnumerablestring lines)
{using var file new System.IO.StreamWriter(WriteLines2.txt);// Notice how we declare skippedLines after the using statement.int skippedLines 0;foreach (string line in lines){if (!line.Contains(Second)){file.WriteLine(line);}else{skippedLines;}}// Notice how skippedLines is in scope here.return skippedLines;// file is disposed here
}
静态本地函数相比非静态本地函数静态本地函数没有闭包因此生成的代码更少性能也更容易控制。int M()
{int y 5;int x 7;return Add(x, y);static int Add(int left, int right) left right;
}
异步流这个功能和 IEnumerableT、 TaskT对应一个经典的表格如下单值多值同步TIEnumerable异步Task?其中这个问号 ?终于有了答案它就叫异步流—— IAsyncEnumerableTpublic static async System.Collections.Generic.IAsyncEnumerableint GenerateSequence()
{for (int i 0; i 20; i){await Task.Delay(100);yield return i;}
}
不像 IEnumerableT IAsyncEnumerableT系统还没有内置扩展方法因此可能没有 IEnumerableT方便但是可以通过安装 NuGet包 f来实现和 IEnumerableT一样或者更爽的效果。索引和范围和 Python中的切片器一样只是 -用 ^代替了。var words new string[]
{// index from start index from endThe, // 0 ^9quick, // 1 ^8brown, // 2 ^7fox, // 3 ^6jumped, // 4 ^5over, // 5 ^4the, // 6 ^3lazy, // 7 ^2dog // 8 ^1
}; // 9 (or words.Length) ^0
var quickBrownFox words[1..4];
var lazyDog words[^2..^0];
var allWords words[..]; // contains The through dog.
var firstPhrase words[..4]; // contains The through fox
var lastPhrase words[6..]; // contains the, lazy and dog
Null合并赋值Listint numbers null;
int? i null;
numbers ?? new Listint();
numbers.Add(i ?? 17);
numbers.Add(i ?? 20);
Console.WriteLine(string.Join( , numbers)); // output: 17 17
Console.WriteLine(i); // output: 17
非托管构造类型与任何非托管类型一样可以创建指向此类型的变量的指针或针对此类型的实例在堆栈上分配内存块SpanCoordsint coordinates stackalloc[]
{new Coordsint { X 0, Y 0 },new Coordsint { X 0, Y 3 },new Coordsint { X 4, Y 0 }
};
嵌套表达式中的 stackallocSpanint numbers stackalloc[] { 1, 2, 3, 4, 5, 6 };
var ind numbers.IndexOfAny(stackalloc[] { 2, 4, 6 ,8 });
Console.WriteLine(ind); // output: 1
附录/总结这么多功能你印象最深刻的是哪个呢参考资料C#发展历史 - C#指南 | Microsoft Docs https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-version-history本文内容和代码由肖鹏整理有大量修改转载已获得肖鹏本人授权。肖鹏是我公司从 Java转 .NET的同事。原文链接为https://akiyax.github.io/new-features-in-csharp/。