当前位置: 首页 > news >正文

What is new in C# 7,8,9,10

目录

What's new in C# 7

C# 7 in Visual Studio 2017

Out Variables

Pattern Matching

Tuples (System.ValueTuple)

 Deconstruct解构

Local Functions

Ref Returns and Locals

Expression Bodied Members

Throw Expressions

Generated Async Return Types

Literal Improvements

C# 7.1 in Visual Studio 2017.3

Compilation Issues (how to switch to C#7.1)

Async Main

Default Expressions

Ref Assemblies

Infer Tuple Names

Pattern-Matching with Generics

C# 7.2 in Visual Studio 2017 15.5

Leading Digit Separators

'Private Protected' Access Modifier

Non-Trailing Named Arguments

Reference Semantics on Value Types值类型的引用语义

C# 7.3 in Visual Studio 2017 15.5

Performance Improvement

Features Enhancements

Extensioned expression variables in initializers

New Compiler Features

What's new in C# 8

Nullable Reference Types

Method 1: 通过引用ReSharper.Annotations

Method 2: 通过使用string?

Override Null Checks

Diable nullable check

Enable nullable check

Index and Range

Default Interface Members

Extension to create Default function in Interface

Default function in iterface

Pattern Matching

What's new in C# 9 (. NET 5)

Record Types

浅拷贝with

Top-level Calls

Initial Setters

Pttern Matching Improvement

Target-Typed New

Source Generators

Partial Method Syntax and Modules Initializers(部分方法语法和模块初始化器)

What's new in C# 10 (. NET 6)

Record Structs

Global Using Directives

File-Scoped Namespace Declarations

Extended Property Patterns

Generic Attributes通用属性

Lambda Improvements,提高很多

Enhanced #line directives



What's new in C# 7

C# 7 in Visual Studio 2017

Out Variables

using System;
using static System.Console;namespace CSharp7Demos
{class OutVariables{static void MainOV(string[] args){DateTime dt; // structif (DateTime.TryParse("01/01/2017", out dt)){WriteLine($"Old-fashioned parse: {dt}");}// variable declaration is an expression, not a statementif (DateTime.TryParse("02/02/2016", out /*DateTime*/ var dt2)){WriteLine($"New parse: {dt2}");}// the scope of dt2 extends outside the if blockWriteLine($"I can use dt2 here: {dt2}");// what if the parse fails?int.TryParse("abc", out var i);WriteLine($"i = {i}"); // default value}}
}

Pattern Matching

using static System.Console;namespace CSharp7Demos
{public class Shape{}public class Rectangle : Shape{public int Width, Height;}public class Circle : Shape{public int Diameter;}public class PatternMatching{public void DisplayShape(Shape shape){if (shape is Rectangle){var rc = (Rectangle) shape;} else if (shape is Circle){// ...}var rect = shape as Rectangle;if (rect != null) // nonnull{//...}if (shape is Rectangle r){// use r}// can also do the invserseif (!(shape is Circle cc)){// not a circle!}switch (shape){case Circle c:// use cbreak;case Rectangle sq when (sq.Width == sq.Height):// square!break;case Rectangle rr:// use rrbreak;}var z = (23, 32);//switch (z)//{//  case (0, 0)://    WriteLine("origin");//}}static void Main(string[] args){}}
}

Tuples (System.ValueTuple)

using System;
using System.Linq;
using Microsoft.SqlServer.Server;
using static System.Console;namespace CSharp7Demos
{public class Point{public int X, Y;public void Deconstruct(out string s){s = $"{X}-{Y}";}public void Deconstruct(out int x, out int y){x = X;y = Y;}}public class Tuples{static Tuple<double, double> SumAndProduct(double a, double b){return Tuple.Create(a + b, a * b);}// requires ValueTuple nuget package// originally with no namesstatic (double sum, double product) NewSumAndProduct(double a, double b){return (a+b,a*b);}static void MainT(string[] args){// Newvar sp = SumAndProduct(2, 5);// sp.Item1 uglyWriteLine($"sum = {sp.Item1}, product = {sp.Item2}");var sp2 = NewSumAndProduct(2, 5);WriteLine($"new sum = {sp2.sum}, product = {sp2.product}");WriteLine($"Item1 = {sp2.Item1}");WriteLine(sp2.GetType());// converting to valuetuple loses all infovar vt = sp2;// back to Item1, Item2, etc...var item1 = vt.Item1; // :(// can use var below//(double sum, var product) = NewSumAndProduct(3, 5);var (sum, product) = NewSumAndProduct(3, 5);// note! var works but double doesn't// double (s, p) = NewSumAndProduct(3, 4);(double s, double p) = NewSumAndProduct(3, 4);//This can workWriteLine($"sum = {sum}, product = {product}");WriteLine(sum.GetType());// also assignmentdouble s, p;(s, p) = NewSumAndProduct(1, 10);// tuple declarations with names//var me = new {name = "Evan", age = 37}; // AnonymousTypevar me = (name: "Evan", age: 37);WriteLine(me);WriteLine(me.GetType());//Print is System.ValueTuple// names are not part of the type:WriteLine("Fields: " + string.Join(",", me.GetType().GetFields().Select(pr => pr.Name)));WriteLine("Properties: " + string.Join(",", me.GetType().GetProperties().Select(pr => pr.Name)));WriteLine($"My name is {me.name} and I am {me.age} years old");// proceed to show return: TupleElementNames in dotPeek (internally, Item1 etc. are used everywhere)// unfortunately, tuple names only propagate out of a function if they're in the signaturevar snp = new Func<double, double, (double sum, double product)>((a, b) => (sum: a + b, product: a * b));var result = snp(1, 2);// there's no result.sum unless you add it to signatureWriteLine($"sum = {result.sum}");}}
}

 Deconstruct解构

// deconstruction
Point pt = new Point {X = 2, Y = 3};
var (x,y) = pt; // interesting error here
Console.WriteLine($"Got a point x = {x}, y = {y}");// can also discard values
(int z, _) = pt;

Local Functions

CalculateDiscriminant可以放在方法SolveQuadratic体内,或者方法体外,放在方法体内是,所在的位置可以在调用前或者调用后面。

建议放在前面,方便代码维护。

  public class Employee{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public string MiddleName { get; set; }//normal ctor//public Employee(string firstName, string lastName, string middleName)//{//    FirstName = firstName;//    LastName = lastName;//    MiddleName = middleName;//}//lambda ctorpublic Employee(string firstName, string lastName, string middleName) => (FirstName, LastName, MiddleName) = (firstName, lastName, middleName);}
using System;namespace CSharpDemos
{public class EquationSolver{//private Func<double, double, double, double> CalculateDiscriminant = (aa, bb, cc) => bb * bb - 4 * aa * cc;//Quadratic 二次方程public static Tuple<double, double> SolveQuadratic(double a, double b, double c){//var CalculateDiscriminant = new Func<double, double, double, double>((aa, bb, cc) => bb * bb - 4 * aa * cc);//double CalculateDiscriminant(double aa, double bb, double cc)//{//  return bb * bb - 4 * aa * cc;//}//double CalculateDiscriminant(double aa, double bb, double cc) => bb * bb - 4 * aa * cc;//double CalculateDiscriminant() => b * b - 4 * a * c;//var disc = CalculateDiscriminant(a, b, c);var disc = CalculateDiscriminant();var rootDisc = Math.Sqrt(disc);return Tuple.Create((-b + rootDisc) / (2 * a),(-b - rootDisc) / (2 * a));// can place heredouble CalculateDiscriminant() => b * b - 4 * a * c;}//private static double CalculateDiscriminant(double a, double b, double c)//{//  return b * b - 4 * a * c;//}}public class LocalFunctions{static void MainT(string[] args){var result = EquationSolver.SolveQuadratic(1, 10, 16);Console.WriteLine(result);}}
}

Ref Returns and Locals

using System;
using System.Collections.Generic;
using static System.Console;namespace CSharpDemos
{public class RefReturnsAndLocals{static ref int Find(int[] numbers, int value){for (int i = 0; i < numbers.Length; i++){if (numbers[i] == value)return ref numbers[i];}// cannot do by value return//return -1;// cannot return a local//int fail = -1;//return ref fail;throw new ArgumentException("meh");}static ref int Min(ref int x, ref int y){//return x < y ? (ref x) : (ref) y;//return ref (x < y ? x : y);if (x < y) return ref x;return ref y;}static void MainRRL(string[] args){// reference to a local elementint[] numbers = { 1, 2, 3 };ref int refToSecond = ref numbers[1];var valueOfSecond = refToSecond;// cannot rebind// refToSecond = ref numbers[0];refToSecond = 123;WriteLine(string.Join(",", numbers)); // 1, 123, 3// reference persists even after the array is resizedArray.Resize(ref numbers, 1);WriteLine($"second = {refToSecond}, array size is {numbers.Length}");refToSecond = 321;WriteLine($"second = {refToSecond}, array size is {numbers.Length}");//numbers.SetValue(321, 1); // will throw// won't work with listsvar numberList = new List<int> {1, 2, 3};//ref int second = ref numberList[1]; // property or indexer cannot be outint[] moreNumbers = {10, 20, 30};//ref int refToThirty = ref Find(moreNumbers, 30);//refToThirty = 1000;// disgusting use of languageFind(moreNumbers, 30) = 1000;WriteLine(string.Join(",",moreNumbers));// too many references:int a = 1, b = 2;ref var minRef = ref Min(ref a, ref b);// non-ref call just gets the valueint minValue = Min(ref a, ref b);WriteLine($"min is {minValue}");}}
}

Expression Bodied Members

using System.Collections.Generic;namespace CSharpDemos
{// community contributed featurepublic class Person{private int id;private static readonly Dictionary<int, string> names = new Dictionary<int, string>();public Person(int id, string name) => names.Add(id, name);~Person() => names.Remove(id);public string Name{get => names[id];set => names[id] = value;}}
}

Throw Expressions

using System;
using static System.Console;namespace CSharpDemos
{public class ThrowExpressions{public string Name { get; set; }public ThrowExpressions(string name){Name = name ?? throw new ArgumentNullException(paramName: nameof(name));}int GetValue(int n){return n > 0 ? n + 1 : throw new Exception();}static void MainTE(string[] args){int v = -1;try{var te = new ThrowExpressions("");v = te.GetValue(-1); // does not get defaulted!}catch (Exception e){Console.WriteLine(e);}finally{WriteLine(v);}}}
}

Generated Async Return Types

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;namespace CSharpDemos
{public class GeneralizedAsyncReturnTypes{public static async Task<long> GetDirSize(string dir){if (!Directory.EnumerateFileSystemEntries(dir).Any())return 0;// Task<long> is return type so it still needs to be instantiatedreturn await Task.Run(() => Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories).Sum(f => new FileInfo(f).Length));}// C# 7 lets us define custom return types on async methods// main requirement is to implement GetAwaiter() method// ValueTask is a good example// need nuget packagepublic static async ValueTask<long> NewGetDirSize(string dir){if (!Directory.EnumerateFileSystemEntries(dir).Any())return 0;// Task<long> is return type so it still needs to be instantiatedreturn await Task.Run(() => Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories).Sum(f => new FileInfo(f).Length));}static void MainGART(string[] args){// async methods used to require void, Task or Task<T>// C# 7 allows other types such as ValueType<T> - prevent// allocation of a task when the result is already available// at the time of awaitingConsole.WriteLine(NewGetDirSize(@"c:\temp").Result);}}
}

Literal Improvements

namespace CSharpDemos
{public class LiteralImprovements{static void MainLI(string[] args){int a = 123_321;int b = 123_321______123;// cannot do trailing//int c = 1_2_3___; // R# remove// also works for hexlong h = 0xAB_BC_D123EF;// also binayvar bin = 0b1110_0010_0011;}}
}

C# 7.1 in Visual Studio 2017.3

Compilation Issues (how to switch to C#7.1)

 以下内码在vs2017.3中会报编译错误,你可以从Solution Explore右击Project-->Properties-->Build --> Advance去更改C#版本到7.1去解决编译错误。

static async Task Main(string[] args){Console.WriteLine("ABC");}

Async Main

using System;
using System.Net.Http;
using System.Threading.Tasks;namespace CSharpDemos
{internal class Program{// used to be the case that your demo// would have to reside in a separate// bodyprivate static string url = "http://google.com/robots.txt";//private static async Task MainAsync(string s)//{//  // blah//  Console.WriteLine(await new HttpClient().GetStringAsync(s));//}//public static void Main(string[] args)//{//  // fine//  MainAsync(url).GetAwaiter().GetResult();//}// there is no async void, it's// Task Main// Task<int> Main if you need to returnstatic async Task Main(string[] args){Console.WriteLine(await new HttpClient().GetStringAsync(url));}}
}

Default Expressions

using System;
using System.Collections.Generic;
using static System.Console;namespace CSharpDemos
{public class DefaultLiteral{// allowed in argument names// only upside: switching from ref to value type// VS Action 'Simplify Default Expression'public DateTime GetTimestamps(List<int> items = default(List<int>)){// ...return default;}/// <summary>/// Default literal, one of the slightly meaningless features./// </summary>static void Main(){// Simplify default expression hereint a = default(int);WriteLine(a);int av = default;//same as above, 0 is int default valueWriteLine(av);int b = default;WriteLine(b);// constants are ok if the inferred type is suitableconst int c = default;WriteLine(c);// will not work here// const int? d = default; // oops// cannot leave defaults on their ownvar e = new[] {default, 33, default};WriteLine(string.Join(",", e));// rather silly way of doing things; null is shorterstring s = default;WriteLine(s == null);// comparison with default is OK if type can be inferredif (s == default){WriteLine("Yes, s is default/null");}// ternary operationsvar x = a > 0 ? default : 1.5;WriteLine(x.GetType().Name);}}
}

Ref Assemblies

利用Refelection反编译后,代码实现部分只有null返回,其他部分被隐藏了。

Infer Tuple Names

using System;
using System.Linq;namespace CSharpDemos
{using static System.Console;public class InferTupleNames{// Tuple projection initializerspublic static void Main(string[] args){// reminder: tuplesvar me = (name: "Evan", age: 37);WriteLine(me);var alsoMe = (me.age, me.name);WriteLine(alsoMe.Item1); // typicalWriteLine(alsoMe.name); // newvar result = new[] {"March", "April", "May"} // explicit name not required.Select(m => (/*Length:*/ m/*?*/.Length, // optionally nullableFirstChar: m[0])) // some names (e.g., ToString) disallowed.Where(t => t.Length == 5); // note how .Length is available hereWriteLine(string.Join(",", result));// tuples produced by deconstructionvar now = DateTime.UtcNow;var u = (now.Hour, now.Minute);var v = ((u.Hour, u.Minute) = (11, 12));WriteLine(v.Minute);}}
}

Pattern-Matching with Generics

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace CSharpDemos
{using static System.Console;public class Animal{}public class Pig : Animal{}public class PatternMatchingWithGenerics{public static void Cook<T>(T animal)where T : Animal{// note the red squiggly!// cast is redundant hereif ((object)animal is Pig pig){// cook and eat itWrite("We cooked and ate the pig...");}switch (/*(object)*/animal){case Pig pork:WriteLine(" and it tastes delicious!");break;}}/// <summary>/// Need to fall back to C# 7 for this./// </summary>static void Main(string[] args){var pig = new Pig();Cook(pig);}}
}

C# 7.2 in Visual Studio 2017 15.5

Leading Digit Separators

  class LeadingUnderscoresNumericSeparators{static void Main(string[] args){// binaryvar x = 0b_1111_0000;// hexvar y = 0x_baad_f00d;}}

'Private Protected' Access Modifier

public class Base{private int a;protected internal int b; // derived classes or classes in same assemblyprivate protected int c;  // containing class or derived classes in same assembly only }class Derived : Base{public Derived(){c = 333; // fineb = 3; // no}}class Foo{static void Main(string[] args){Base pp = new Base();var d = new Derived();d.b = 3;// d.c is a no-go}}

Non-Trailing Named Arguments

static void doSomething(int foo, int bar){}static void Main(string[] args){doSomething(foo: 33, 44);// still illegal//doSomething(33, foo:44)}

Reference Semantics on Value Types值类型的引用语义

'In' Parameters

'Ref Readonly' Variables

'Ref Struct' and Span

struct Point{public double X, Y;public Point(double x, double y){X = x;Y = y;}public void Reset(){X = Y = 0;}// we don't want to recreate origin as new Point(), so...private static Point origin = new Point();public static ref readonly Point Origin => ref origin;public override string ToString(){return $"({X},{Y})";}}public class RefSemanticsValueTypes{// IN PARAMETERSvoid changeMe(ref Point p){p.X++;}// structs are passed by reference (i.e. address, so 32 or 64 bits)// 'in' is effectively by-ref and read-onlydouble MeasureDistance(in Point p1, in Point p2){// cannot assign to in parameter// p1 = new Point();// cannot pass as ref or out method// obvious// changeMe(ref p2);p2.Reset(); // instance operations happen on a copy!var dx = p1.X - p2.X;var dy = p1.Y - p2.Y;return Math.Sqrt(dx * dx + dy * dy);}// cannot create overloads that differ only in presence?// yeah you can, but//double MeasureDistance(Point p1, Point p2)//{//  return 0.0;//}public RefSemanticsValueTypes(){var p1 = new Point(1, 1);var p2 = new Point(4, 5);var distance = MeasureDistance(p1, p2);//             ^^^^ call ambiguousConsole.WriteLine($"Distance between {p1} and {p2} is {distance}");// can also pass in temporariesvar distFromOrigin = MeasureDistance(p1, new Point());var alsoDistanceFromOrigin = MeasureDistance(p2, Point.Origin);// REF READONLY RETURNS// make an ordinary by-value copyPoint copyOfOrigin = Point.Origin;// it's readonly, you cannot do a ref!//ref var messWithOrigin = ref Point.Origin;ref readonly var originRef = ref Point.Origin;// won't work//originRef.X = 123;}// REF STRUCTS// a value type that MUST be stack-allocated// can never be created on the heap// created specifically for Span<T>class CannotDoThis{Span<byte> stuff;}static void Main(string[] args){new RefSemanticsValueTypes();unsafe{// managedbyte* ptr = stackalloc byte[100];Span<byte> memory = new Span<byte>(ptr, 100);// unmanagedIntPtr unmanagedPtr = Marshal.AllocHGlobal(123);Span<byte> unmanagedMemory = new Span<byte>(unmanagedPtr.ToPointer(), 123);Marshal.FreeHGlobal(unmanagedPtr);}// implicit castchar[] stuff = "hello".ToCharArray();Span<char> arrayMemory = stuff;// string is immutable so we can make a readonly spanReadOnlySpan<char> more = "hi there!".AsSpan();Console.WriteLine($"Our span has {more.Length} elements");arrayMemory.Fill('x');Console.WriteLine(stuff);arrayMemory.Clear();Console.WriteLine(stuff);}}

C# 7.3 in Visual Studio 2017 15.5

Performance Improvement

    • Fixed-sized buffers
    • Ref local variables maybe reassigned
    • stackalloc arrays support initializers
    • int* pArr1=stackalloc int[3]{1,2,3}
      int* pArr2=stackalloc int[]{1,2,3}

Features Enhancements

  • Attributes on backing fields of auto-props (auto-props的后置字段上的属性)
[field:SomeCleverAttribute]
public float SomeProperty{get;set;}

Extensioned expression variables in initializers

public class B
{public B(int i,out int j){j=i;    }
}
public class D:B
{public D(int i):B(i,out var j){Console.WriteLine($"j = {j}}");  }
}
    • Tutple support == and !=
    • Imrpove overload resolution rules for method groups

New Compiler Features

    • --deterministic
    • --publicsign

What's new in C# 8

Nullable Reference Types

Method 1: 通过引用ReSharper.Annotations

[CanBeNull] Foo foo 会被解析为 Foo? foo

[CanBeNull] string middleName会被解析为string? middleName

   public class Employee{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }[CanBeNull] public string MiddleName { get; set; }//CanBeNull is coming from ReSharper.Annotations on NuGetpublic Employee(string firstName, string lastName, [CanBeNull] string middleName) => (FirstName, LastName, MiddleName) = (firstName, lastName, middleName);public string FullName => $"{FirstName} {MiddleName} {LastName}";}

Method 2: 通过使用string?

    public class Employee{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public string? MiddleName { get; set; }//[CanBeNull] public string MiddleName { get; set; }//CanBeNull is coming from ReSharper.Annotations on NuGet//public Employee(string firstName, string lastName, [CanBeNull] string middleName) => (FirstName, LastName, MiddleName) = (firstName, lastName, middleName);public Employee(string firstName, string lastName, string? middleName) => (FirstName, LastName, MiddleName) = (firstName, lastName, middleName);public string FullName => $"{FirstName} {MiddleName} {LastName}";}

以下代码会提示一个Warning:MiddleName maybe null here. CS8602:Dereference  of a possible null reference.

public string FullName => $"{FirstName} {MiddleName[0]} {LastName}";

If nullability is enabled 

string? ≠ Nullable<string>

string? is still a string, but we need null checks.

public string FullName => $"{FirstName} {MiddleName?[0]} {LastName}";
        void Test(){string? str = GetString();//Will get warning belowchar c = str[0];//no warningif (str != null){char c2 = str[0];}}
Override Null Checks

2 ways to stop null checks

  • 1. Keep the variable non-nullable
public string MiddleName { get; set; } = string.Empty;
  • 2. Write expression with a bang(!)
public string MiddleName { get; set; } = null!;  
//Warning(null as Employee).FullName//No Warning(null as Employee)!.FullName//No Warning. !可以随便输入多少个,都是合法的(null as Employee)!!!!!!!!!.FullName
Diable nullable check

Edit **csproj file

 <Nullable>disable</Nullable>
Enable nullable check

Edit **csproj file,it is default setting.

<Nullable>enable</Nullable>

Code in below are no warning. 

//No warning
Type t = Type.GetType(nameof(Employee));
string name = t.Name; //No warning
Type? t2 = Type.GetType(nameof(Employee));
string name = t2.Name; 

Index and Range

Points into an array

  • Value
  • IsFromEnd
    Index ids = 2;//implict conversionIndex idx2 = new Index(0, false);var idx3 = ^0;//Index (0, true)// -1 is not last
//Index
var items = new[] { 1, 2, 3, 4 };
items[^2] = 33;//^2 去倒数第二个数值
Console.WriteLine($"{string.Join(",", items)}");//1,2,33,4//Range from a[X...Y] means from a[X] to a[Y].
//If X > Y will through ArgumentOutOfRangeException
items = new[] { 1, 2, 3, 4 };
var items2 = items[0..2];//从第一个开始取值,总共取两个值
Console.WriteLine($"{string.Join(",", items2)}");//1,2//Index + Range
var items3 = items[0..^0];//从第一个开始取值,取到最后一个值
Console.WriteLine($"{string.Join(",", items3)}");//1,2,3,4//Array slices yield copies
var test = items[..2];//Create a copy
Console.WriteLine($"{string.Join(",", test)}");//1,2
var test2 = items.AsSpan<int>();//{1,2,3,4}
Console.WriteLine("Span");
foreach (var item in test2)
{Console.WriteLine($"{item}");
}

Default Interface Members

Extension to create Default function in Interface

    public interface IHuman{string Name { get; set; }}public static class HumanExtension{public static void SayHello(this IHuman human){Console.WriteLine($"Hello, I am {human.Name}");}}

Default function in iterface

It is same behavior with above code.

    public interface IHuman{string Name { get; set; }public void SayHello(){Console.WriteLine($"Hello, I am {Name}");}}

Call demo:

//Human human2 = new Human("Alex");
//human2.SayHello();//Compiler errorIHuman human = new Human("Alex");
human.SayHello();//Hello, I am Alex((IHuman)new Human("Alex")).SayHello();//Hello, I am Alex

 Interface override

    public class IFrieldlyHuman : IHuman//IHuman is same with code in above{public string Name { get; set; }public void SayHello(){Console.WriteLine($"Greeting, I am {Name}");}}public class Human2 : IFrieldlyHuman{public Human2(string name){Name = name;}}//call demo
((IFrieldlyHuman)new Human2("Alex")).SayHello();//Greeting, I am Alex

Pattern Matching

哪个人设计的这个绕的写法。。。

    struct PhoneNumer{public int Code, Number;}private void TestPhone(){var phoneNumer = new PhoneNumer();string? origin;//哪个人设计的这种写法,难读的要命origin = phoneNumer switch{{ Number: 110 } => "Police",{ Code: 86 } => "China",{ } => null};//个人还是喜欢下面的写法switch (phoneNumer){case { Number: 110 }:origin = "Police";break;case { Code: 86 }:origin = "China";break;default:origin = null;break;}}

What's new in C# 9 (. NET 5)

Record Types


var p = new Person() { Name = "Evan", Age = 37 };
var p2 = new Person() { Name = "Evan", Age = 37 };
Console.WriteLine(p);//Print: Person { Name = Evan, Age = 37, Address =  }
Console.WriteLine(p2);//Print: Person { Name = Evan, Age = 37, Address =  }
Console.WriteLine($"p==p2? {p == p2}");//Print: p==p2? truevar address = new Address() { AreaCode = 123456, Stress = "星火北路8号" };
var address2 = new Address() { AreaCode = 123456, Stress = "药谷大道8号" };
Console.WriteLine($"address==address2? {address == address2}");//Print: address==address2? falsep.Address = address;
p2.Address = address;
Console.WriteLine($"p==p2? {p == p2}");//Print: p==p2? true
p2.Address = address2;
Console.WriteLine($"p==p2? {p == p2}");//Print: p==p2? falsepublic record Person
{public string Name { get; set; }public int Age { get; set; }public Address Address { get; set; }
}public class Address
{public int AreaCode { get; set; }public string Stress { get; set; }
}

浅拷贝with

Car car = new() { Engine = "V6", Color = new CarColor() { Name = "Black", Metallic = false } };
Car upgradeCar = car with { Engine = "V8" };//Clone()=shallow copy. 浅拷贝
upgradeCar.Color.Metallic = true;
Console.WriteLine(car);//Print: Car { Engine = V6, Color = CarColor { Name = Black, Metallic = True } }
Console.WriteLine(upgradeCar);//Print: Car { Engine = V8, Color = CarColor { Name = Black, Metallic = True } }
public record Car
{public string Engine { get; set; }public CarColor Color { get; set; }
}
public record CarColor
{public string Name { get; set; }public bool Metallic { get; set; }
}

Top-level Calls

Program.cs 没有namespace了。


Console.WriteLine("Hello, World!");Foo();void Foo()
{Console.WriteLine("Hello, Foo!");
}

Initial Setters

    public class Demo{//readonly filed only can set value in initial or in ctorpublic readonly string Filed = "ABC";public Demo(string filed){Filed = filed;}}
    public class Demo{//Inital only can set value in the class it ctor, not by call or functionpublic int Age { get; init; }public Demo(int filed){Age = filed;}//Below code will get errorpublic void ChangeValue(int newValue){Age = newValue;}}public class CallDemo{void Main(){//Below code will get errorvar p = new Demo() { Age = 37 };}}

Pttern Matching Improvement

object obj;
if (obj is not null)
{}
if (obj is not string)//same as !(obj is string)
{}int temperature = 40;
var feel = temperature switch
{< 0 => "冷",>= 0 and < 20 => "温暖",>= 20 and not 40 => "热",40 or 666 => "热死了"
};
Console.WriteLine(feel);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 ',';

Target-Typed New

Person p=new Person();var p2=new Person();Person p=new();

Source Generators

Microsoft.CodeAnalysis.Analyzers, NugGet, ISourceGenerator

T4

using Microsoft.CodeAnalysis;
namespace Gen
{[Generator]public class Generator : ISourceGenerator{public void Execute(GeneratorExecutionContext context){var source=@"class Foo{public string Bar=""bar"";}";context.AddSource("Gen.cs",source)}public void Execute(GeneratorInitializationContext context){}}
}//更改.csproj <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles><CompilerGeneratedFilesOutputPath>c:\temp</CompilerGeneratedFilesOutputPath>//Build 完成后,在c:\temp\Gen\GenGenerator 会生成一个Gen.cs文件

Partial Method Syntax and Modules Initializers(部分方法语法和模块初始化器)

Startup.cs in API

What's new in C# 10 (. NET 6)

Visual Studio go to x64.

Record Structs

Same as Record class, but value types

Synthesuized members合成的成员

  •         Constructure,Deconstructure,Equals/==/!=, GetHashCode, PrintMembers, ToString

Predictable differences to record classes

  • Eg: Equals() does not do null check

Performance can be significantly better than ordinary structs

  • Also better than value Tuple
  • Default Equals()/GetHaskCode() implementations are bad (boxing etc.)
  • Record struct can be 20x faster with 100% less allocations

Restrictions

  • Cannot have a clone member
  • Instance field cannot be unsafe
  • annot declare a destructor
//small, composite value types
record struct Point<T>(T x, T y){...}
Point<int> p=new (100,200);//Record structs are mutable(可变的)
//Mutable structs are dangerous
player.Position.X++;// does nothing. means don't change anything//Recommend:
record struct Point2<T>(T x, T y){...}
p.X++;//will not compile

Global Using Directives

using System has been replaced because we have global using System.

我们可以创建一个GlobalUsings.cs,把常用的引用放在里面。

.NET6 project included several global usings that are implicit(隐式的):

<ImplicitUsings>enable</ImplicitUsings>

File-Scoped Namespace Declarations

vs有工具去选择“”Tofile-scoped namespace“”

Extended Property Patterns

static void Test()
{object obj;//Check properties using dot notationif (obj is Developer { Manager.FirstName: "Sam" } d){Console.WriteLine(d.Manager.FirstName);}//Check multiple patterns and arbitrary(任意的) depthif (obj is Developer { Manager.FirstName.Length: 5, Manager.yearOfWork: 10 } d2){Console.WriteLine(d2.Manager.FirstName);}
}public class Developer
{public string FirstName { get; set; }public string LastName { get; set; }public Manager Manager { get; set; }
}public class Manager
{public string FirstName { get; set; }public string LastName { get; set; }public int yearOfWork { get; set; }
}

Generic Attributes通用属性

//Current approacgh to taking a type in an attribute
class MyAttribute: Attribute
{MyAttribute(Type type){...}//伪代码
}
//usege 
[My(typeof(Foo))]//Now we can use type parameters instead:
class My Attribute
{...
}
//usege 
[My<float>] public void Bar(){...}//Type parameters from containing type cannot be used in attributes.eg:
public class Program<T>
{[SomeAttr<T>] void Foo(){...}//got error[SomeAttr<List<T>>] void Foo(){...}//got error
}

Lambda Improvements,提高很多

//Add attributes to lambda
var f=[A]{}=>{...};
//Demo:
var f=[return:A] x=>x;//syntax error at '=>', wrong demo
var f=[return:A] (x)=>x;//[A] lambda. Correct demo//Multiple attributes
var f=[a1,a2][a3]()=>{};
var f2=([a1][a2,a3] int x)=>x;//Attributes not support in delegate. will get error in below code:
f=[a] delegate {return 1;}// syntax error at 'delegate'
f=delegate ([a] int x) {return 1;}// syntax error at '['//Collection initializers also use [a] syntax,so, the parser will differences:
var f=new C {[A]=x};//means: f[A]=x
var f2=new C {[A] x=>x};//means: f2[0]=[A] x=>x//? (conditional element), cannot go in front:
x=b? [A];// correct
y=b? [A] ()=>{}:z;//error, syntax error at '('//Explict return type
//You can specify an explicit return type before the parameters
f=T()=>{};//correct
f= ref int (ref int x) => ref x;//correct
f=static void (_) => {};//correct//Not support delegate{} syntax
f= delegate int {retur 1;};// syntax error
f= delegate int (int x) {return x;};//syntax error//Exact method type inference from lambda return:
static void F<T> (Func<T,T> f) {...}
F(int (i) => i);//Func<int,int>//Varaibles conversion not allowed from lambda return type to delegate return type:
Func<object> f = string ()=> 'Evan';//error
Func<object?> f2 = object()=>x; //Warning//Lambda expressions with ref return types are allowed within expressions (without additional parens圆括号)
d= ref int () =>x;// equals: d=(ref int () => x)
F(ref int() => x);// equals: F((ref int() => x))//Var cannot be used as explicit return type
d=var (var x)=>x;//Error: contextula keyword 'var' cannot be used as explicit lambda return type//Lambda will be infered to Action/Func<>
var f =()=>1;// System.Func<int>
var f2 = string() => "Evan";// System.Func<string>
var f3 = delegate (object o) (object o) {};// System.Action<object>

Enhanced #line directives

debug/diagnostics/if**

#if ANYCPU
...
#endif#if DEBUG
...
#endif

http://www.lryc.cn/news/440589.html

相关文章:

  • Sqlserver常用sql
  • 基于SpringBoot+Vue+MySQL的考研互助交流平台
  • chatgpt个人版ssrf漏洞
  • 如何查看微信聊天记录?四种实用方法查询微信聊天记录,赶快码住!
  • 钢材表面缺陷数据集以coco格式做好了数据集的划分,1200张训练集,600张验证集,对应的json文件也在里面
  • 【Lua坑】Lua协程coroutine无法正常完整执行问题
  • istio中serviceentry结合egressgateway的使用
  • 使用 Python 实现 Windows 应用图标的便捷生成:一站式 PNG 转 ICO 工具20240918
  • 编程环境常用命令合集
  • Qt Creator 集成开发环境 常见问题
  • 使用Faiss进行K-Means聚类
  • 通过hosts.allow和hosts.deny限制用户登录
  • PWN College 关于sql盲注
  • 【Linux篇】Http协议(1)(笔记)
  • 员工疯狂打CALL!解锁企业微信新玩法,2024年必学秘籍来啦!
  • Spring boot从0到1 - day01
  • Flutter 项目结构的区别
  • EfficientFormerV2:重新思考视觉变换器以实现与MobileNet相当的尺寸和速度。
  • ASP.NET Core高效管理字符串集合
  • vm-tools的卸载重装,只能复制粘贴,无法拖拽文件!
  • Docker 容器网络技术
  • C++ 起始帧数、结束帧数、剪辑视频
  • 【项目一】基于pytest的自动化测试框架———解读requests模块
  • 升级Ubuntu内核的几种方法
  • Android绘制靶面,初步点击位置区域划分取值测试
  • 【SpringBoot】调度和执行定时任务--Quartz(超详细)
  • 低代码开发平台系统架构概述
  • 源码编译llama.cpp 、ggml 后端启用自定义BLAS加速
  • glb数据格式
  • 手语识别系统源码分享