C#2:
1.泛型
C#3:
1.主要是linq
2.拉姆达表达式
C#4:
1.可选参数
2.异步 async ... await ...
异步的例子:
C#5:
C#6:
1. ?.操作符,和??操作符类似
2. using静态指令。using static <静态方法的类名>,就可以在下文中,只写静态方法,而不用带出类名。
参考地址:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/using-static
3.
using System; public class Circle { public Circle(double radius) { Radius = radius; } public double Radius { get; set; } public double Diameter { get { return 2 * Radius; } } public double Circumference { get { return 2 * Radius * Math.PI; } } public double Area { get { return Math.PI * Math.Pow(Radius, 2); } } }
使用Math类使用using静态指令后,使用Math类中的静态方法和静态成员就不用了带类名了。
using System; using static System.Math; public class Circle { public Circle(double radius) { Radius = radius; } public double Radius { get; set; } public double Diameter { get { return 2 * Radius; } } public double Circumference { get { return 2 * Radius * PI; } } public double Area { get { return PI * Pow(Radius, 2); } } }
3. case () when 语句
using System; public abstract class Shape { public abstract double Area { get; } public abstract double Circumference { get; } } public class Rectangle : Shape { public Rectangle(double length, double width) { Length = length; Width = width; } public double Length { get; set; } public double Width { get; set; } public override double Area { get { return Math.Round(Length * Width,2); } } public override double Circumference { get { return (Length + Width) * 2; } } } public class Square : Rectangle { public Square(double side) : base(side, side) { Side = side; } public double Side { get; set; } } public class Example { public static void Main() { Shape sh = null; Shape[] shapes = { new Square(10), new Rectangle(5, 7), new Rectangle(10, 10), sh, new Square(0) }; foreach (var shape in shapes) ShowShapeInfo(shape); } private static void ShowShapeInfo(Object obj) { switch (obj) { case Shape shape when shape.Area == 0: Console.WriteLine($"The shape: {shape.GetType().Name} with no dimensions"); break; case Square sq when sq.Area > 0: Console.WriteLine("Information about the square:"); Console.WriteLine($" Length of a side: {sq.Side}"); Console.WriteLine($" Area: {sq.Area}"); break; case Rectangle r when r.Area > 0: Console.WriteLine("Information about the rectangle:"); Console.WriteLine($" Dimensions: {r.Length} x {r.Width}"); Console.WriteLine($" Area: {r.Area}"); break; case Shape shape: Console.WriteLine($"A {shape.GetType().Name} shape"); break; case null: Console.WriteLine($"The {nameof(obj)} variable is uninitialized."); break; default: Console.WriteLine($"The {nameof(obj)} variable does not represent a Shape."); break; } } } // The example displays the following output: // Information about the square: // Length of a side: 10 // Area: 100 // Information about the rectangle: // Dimensions: 5 x 7 // Area: 35 // Information about the rectangle: // Dimensions: 10 x 10 // Area: 100 // The obj variable is uninitialized. // The shape: Square with no dimensions
catch( ) when 语句
using System; using System.Net.Http; using System.Threading.Tasks; class Program { static void Main() { Console.WriteLine(MakeRequest().Result); } public static async Task<string> MakeRequest() { var client = new HttpClient(); var streamTask = client.GetStringAsync("https://localHost:10000"); try { var responseText = await streamTask; return responseText; } catch (HttpRequestException e) when (e.Message.Contains("301")) { return "Site Moved"; } catch (HttpRequestException e) when (e.Message.Contains("404")) { return "Page Not Found"; } catch (HttpRequestException e) { return e.Message; } } }
5.表达式主体定义
public override string ToString() => $"{fname} {lname}".Trim(); //等效于 public override string ToString() { return $"{fname} {lname}".Trim(); }
6. $
特殊字符将字符串文本标识为内插字符串
string name = "Mark"; var date = DateTime.Now; // Composite formatting: Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date); // String interpolation: Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now."); // Both calls produce the same output that is similar to: // Hello, Mark! Today is Wednesday, it's 19:40 now.
C#7:
1.元组(Tuple)
(string Alpha, string Beta) namedLetters = ("a", "b"); Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");
或者变量声明用var
var alphabetStart = (Alpha: "a", Beta: "b"); Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");
构造函数中有Deconstruct,在生成对象时,可以提取你需要的属性值
public class Point { public Point(double x, double y) => (X, Y) = (x, y); public double X { get; } public double Y { get; } public void Deconstruct(out double x, out double y) => (x, y) = (X, Y); } var p = new Point(3.14, 2.71); (double X, double Y) = p;
弃元
当提取出来的数据不需要时,用‘_’占位符号,来放弃当前的变量
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
is 运算符添加了一些功能,如下,如果input可以转换为int类型,就把转换后的值赋值给count.
if (input is int count) sum += count;
switch( )增加了一些新功能
public static int SumPositiveNumbers(IEnumerable<object> sequence) { int sum = 0; foreach (var i in sequence) { switch (i) { case 0: break; case IEnumerable<int> 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; }
async main,main方法前面可以添加async修饰符号
static int Main() { return DoAsyncWork().GetAwaiter().GetResult(); } 可以写成下面 static async Task<int> Main() { // This could also be replaced with the body // DoAsyncWork, including its await expressions: return await DoAsyncWork(); } 如果没有返回证人数字,可以返回一个task static async Task Main() { await SomeAsyncMethod(); }
本地函数
public static IEnumerable<char> 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(); IEnumerable<char> alphabetSubsetImplementation() { for (var c = start; c < end; c++) yield return c; } }
throw表达式
private static void DisplayFirstNumber(string[] args) { string arg = args.Length >= 1 ? args[0] : throw new ArgumentException("You must supply an argument"); if (Int64.TryParse(arg, out var number)) Console.WriteLine($"You entered {number:F0}"); else Console.WriteLine($"{arg} is not a number."); }
默认文本表达式
Func<string, bool> whereClause = default(Func<string, bool>); 可以写成这样 Func<string, bool> whereClause = default;
C#4中有了命名参数,C#7.2中方法的命名参数只要和参数的默认顺序相同,也是可以不写出参数名称的
PrintOrderDetails("Gift Shop", 31, "Red Mug"); PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop"); PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31); 也可以这样写 PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); // This generates CS1738: Named argument specifications must appear after all fixed arguments have been specified. PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
in 参数修饰符,表明该参数被作为引用类型来传递,且不能被方法修改
static void M(S arg); static void M(in S arg);
C#8:
switch语句的升级
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)), }; 和下面的一样的功能 public static RGBColor FromRainbowClassic(Rainbow colorBand) { switch (colorBand) { case Rainbow.Red: return new RGBColor(0xFF, 0x00, 0x00); case Rainbow.Orange: return new RGBColor(0xFF, 0x7F, 0x00); case Rainbow.Yellow: return new RGBColor(0xFF, 0xFF, 0x00); case Rainbow.Green: return new RGBColor(0x00, 0xFF, 0x00); case Rainbow.Blue: return new RGBColor(0x00, 0x00, 0xFF); case Rainbow.Indigo: return new RGBColor(0x4B, 0x00, 0x82); case Rainbow.Violet: return new RGBColor(0x94, 0x00, 0xD3); default: throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)); }; }
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" };
using语句,在作用于的结尾,对象会被销毁
static int WriteLinesToFile(IEnumerable<string> lines) { using var file = new System.IO.StreamWriter("WriteLines2.txt"); 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 }
以前的写法需要把using语句写在小括号里
static int WriteLinesToFile(IEnumerable<string> lines)
{
using (var file = new System.IO.StreamWriter("WriteLines2.txt"))
{
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
return skippedLines;
} // file is disposed here
}
引用类型也可为空,类似于可为空的值类型int?,string?
数组的索引和范围
var words = new string[] { // index from start index from end "The", // 0 ^9 "quick", // 1 ^8 "brown", // 2 ^7 "fox", // 3 ^6 "jumped", // 4 ^5 "over", // 5 ^4 "the", // 6 ^3 "lazy", // 7 ^2 "dog" // 8 ^1 }; // 9 (or words.Length) ^0 Console.WriteLine($"The last word is {words[^1]}"); // writes "dog" var quickBrownFox = words[1..4]; 从第二个到第5个 var lazyDog = words[^2..^0]; //从倒数第3个到倒数第一个 var allWords = words[..]; // contains "The" through "dog". var firstPhrase = words[..4]; // contains "The" through "fox" var lastPhrase = words[6..]; // contains "the", "lazy" and "dog" Range phrase = 1..4; var text = words[phrase];
??=操作符,只有左边为null时,才把??=右边的值赋值给左边
List<int> numbers = null; int? i = null; numbers ??= new List<int>(); numbers.Add(i ??= 17); numbers.Add(i ??= 20); Console.WriteLine(string.Join(" ", numbers)); // output: 17 17 Console.WriteLine(i); // output: 17
处理字符串的$ 和 @可以嵌套使用,例如$@"..."
C#9
使用new生成对象时,可以不写类型
private List<WeatherObservation> _observations = new();
判断条件的优化
public static bool IsLetter(this char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
public static bool IsLetterOrSeparator(this char c) =>
c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',';
if (e is not null)
{
// ...
}