ªð¦^¦Cªí ¤W¤@¥DÃD µo©«

[Âà¶K] C# 7.0 ·s¥\¯à¤¶²Ð(2/2)

[Âà¶K] C# 7.0 ·s¥\¯à¤¶²Ð(2/2)

https://blogs.msdn.microsoft.com/msdntaiwan/2017/04/10/c7-new-features/
³o½g¤å³¹¤¶²Ð¤F C# 7.0 ªº·s»yªk¡C³o¤]¬O¦b 2017/03/07 µoªíªº Visual Studio 2017 ¤¤²³¦h·s¥\¯à¤§¤@¡C

±µÄò¤W¤@½g¡G
http://forum.twbts.com/viewthread.php?tid=20801&extra=

Desconstruction (¸Ñºc )
¥t¤@­Ó¨Ï¥Î tuples ªº¤è¦¡¬O±N¥L­Ì deconstruct (¸Ñºc)¡CDeconstructing declaration (¸Ñºc«Å§i) ¬O¥Î¨Ó±N tuple (©Î¬O¨ä¥L­È) ¸Ì­±ªº³¡¤À©î¸Ñ¨Ã­Ó§O«ü¬£¨ì¨ä¥L·sªºÅܼƥΪº»yªk:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");
¦b deconstructing declaration (¸Ñºc«Å§i) ¤¤¡A¥i¥H¦b­Ó§OªºÅܼƤW¨Ï¥Î var:

(var first, var middle, var last) = LookupName(id1); // var inside
¬Æ¦Ü§A¥i¥H¦b¬A¸¹¥~­±¥u¥Î³æ¤@¤@­Ó var:

var (first, middle, last) = LookupName(id1); // var outside
§A¤]¥i¥H³z¹L deconstructing assignment (¸Ñºc«ü¬£) ±N tuple ¸Ñºc«á«ü¬£¨ì¤@­Ó¬J¦³ªºÅܼÆ:

(first, middle, last) = LookupName(id2); // deconstructing assignment
Deconstruction ¤£¥u¾A¥Î©ó tuple¡A¥ô¦ó«¬§O¥u­n¥¦¥]§t deconstructor (¸Ñºc¦¡, µL½×¬O©w¸q
¦b instance method ©Î¬O extension method ³£¥i¥H) ¡A´N¥i¥H³Q¸Ñºc:

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }
¦b³o­Ó deconstructor ¸Ì©w¸qªº©Ò¦³ out °Ñ¼Æ¡A´N¬O¸Ó«¬§Oª«¥ó¸Ñºc«áªº©Ò¦³¶µ¥Ø¡C
(¬°¦ó¦b³oÃä§Ú­Ì¨Ï¥Î out °Ñ¼Æ¡A¦Ó¤£ª½±µ¶Ç¦^ tuple ? ¦]¬°³o¼Ë´N¥i¥HÅý§A¬°¤£¦P¼Æ¶qªº
ÅܼơA¤À§O©w¸q¦h­Ó overloads (¦h¸ü))

class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}

(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);
§A¥i¥H¥Î³o¼Ë±`¨£ªº¼Ò¦¡¡AÅý constructor »P deconstructor ªº°Ñ¼Æ¹ïºÙ±Æ¦C¡C
´N¦p¦P out Åܼƪº»yªk¡A§Ú­Ì¤¹³\§A¦b deconstructor ¤¤ "©¿²¤" §A¤£¦b·Nªº out °Ñ¼Æ:

(var myX, _) = GetPoint(); // I only care about myX
Ķµù: ½Ð¤Å±N³o¸Ì¤¶²Ðªº deconstructor »P¤@¯ëª«¥ó¾É¦V»y¨¥ (¦p: C++, C# ³£¦³) ±`¨£ªº descructor ·d²V¤F¡C
³o­Ó¬q¸¨¤¶²Ðªº C# ¸Ñºc¦¡ (deconstructor), ¬O©w¸qª«¥ó¦p¦ó "©î¸Ñ" ¬°¦h­Ó¿W¥ßªºÅܼơC©î¸Ñ«á­ìª«¥ó¤´µM¦s¦b¡C
¦Ó C# »P constructor («Øºc¦¡) §@¥Î¬Û¤Ïªº descructor (¸Ñºc¨ç¦¡), «h¬O©w¸qª«¥ó­n³Q¾P·´«e¥²¶·°õ¦æªº°Ê§@¡C
¨âªÌªº¤¤¤åĶ¦W³£¦P¼Ë¬O "¸Ñºc" ½Ð¯S§O¯d·N¡C
¹ï©ó C# descructor ªº»¡©ú¡A¥i¥H°Ñ¦Ò: https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

Local functions (°Ï°ì¨ç¦¡)
¦³®É¡A»²§U¨ç¦¡¥u¦³¦b¨Ï¥Î¥Lªº¨ç¦¡¤º¤~¦³·N¸q¡C²{¦b³oºØ±¡ªp¤U¡A§A¥i¥H¦b¨ä¥L¨ç¦¡¤º«Å§i local functions (°Ï°ì¨ç¦¡):

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);
    }
}
¦b local function (°Ï°ì¨ç¦¡) ¤º¡A¥i¥Hª½±µ¨Ï¥Î«Ê³¬°Ï¶ô¤ºªº parameters (°Ñ¼Æ) »P local variables (°Ï°ìÅܼÆ)¡A¥Îªk¤Î³W«h´N¸ò lambda ¹Bºâ¦¡ ªº¥Îªk¤@¼Ë¡C

Á|¨Ò¨Ó»¡¡Aiterator method ³q±`¥~­±³£»Ý­n¥]ÂÐ¥t¤@­Ó non-iterator method ¡A¥Î¨Ó¦b©I¥s®É°µ°Ñ¼ÆÀˬd (iteraotr ¦b³o®É¨Ã¤£·|°õ¦æ¡A¦Ó¬O¦b MoveNext() ³Q©I¥s®É¤~·|±Ò°Ê)¡C³o®É local function ´N«D±`¾A¦X¦b³o¸Ì¨Ï¥Î:

public IEnumerable<T> Filter<T>(IEnumerable<T> source, Func<T, bool> filter)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (filter == null) throw new ArgumentNullException(nameof(filter));

    return Iterator();

    IEnumerable<T> Iterator()
    {
        foreach (var element in source)
        {
            if (filter(element)) { yield return element; }
        }
    }
}
¦P¼Ëªº¨Ò¤l¡A¤£¥Î local function ªº¸Ü¡A´N¥²¶·§â¸Ó method ©w¸q¦b Filter «á­±¡A±N iterator «Å§i¬° private method¡C³o¼Ë·|¾É­P«Ê¸Ë©Ê³Q¯}Ãa: ¨ä¥L¦¨­û¥i¯à·N¥~ªº¨Ï¥Î¥¦ (¦Ó¥B°Ñ¼ÆÀˬd·|³Q²¤¹L)¡C¦P®É¡A©Ò¦³­ì¥» local function »Ý­n¨ú¥Îªº°Ï°ìÅܼƻP°Ñ¼Æ¡A³£¥²¶·°µ¤@¼Ëªº³B²z (Åܦ¨ private members)¡C

§ï¨}ªº Literal
C# 7.0 ¤¹³\¦b number literal (¼Æ¦r±`¼Æ) ¤¤¡A¥Î _ ·í§@ digit separator (¼Æ¦r¤À¹j¾¹):

var d = 123_456;
var x = 0xAB_CD_EF;
§A¥i¥H±N _ ©ñ¦b¼Æ¦r¤¤ªº¥ô¦ó¦ì¸m¡A¨Ó´£°ªµ{¦¡½Xªº¥iŪ©Ê¡A§¹¥þ¤£·|¹ï¼Æ­È¥»¨­¦³¥ô¦ó¼vÅT¡C

¦¹¥~¡AC# 7.0 ¤]¤Þ¤J¤G¶i¦ìªº±`¼Æªí¥Ü¤è¦¡¡A§A²{¦b¥i¥Hª½±µ¥Î¤G¶i¦ìªº¤è¦¡¨Ó¨ú¥N¹L¥h¤Q¤»¶i¦ì (¨Ò: 0x001234) ªºªí¥Ü¤è¦¡¡C¨Ò¦p:

var b = 0b1010_1011_1100_1101_1110_1111;

Ref returns »P ref locals
¦p¦P§A¥i¥H¦b C# ¥Î°Ñ¦Òªº¤è¦¡¶Ç»¼°Ñ¼Æ (¨Ï¥Î ref ­×¹¢µü)¡A§A²{¦b¤]¥i¥H¥Î¦P¼Ëªº¤è¦¡±N°Ï°ìÅܼƪº¼Æ­È¥Î°Ñ¦Òªº¤è¦¡¶Ç¦^¡C

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers == number)
        {
            return ref numbers; // 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
³o¦b¦^¶Ç¤j«¬¸ê®Æµ²ºc®É¬Û·í¦³¥Î¡CÁ|¨Ò¨Ó»¡¡A¹CÀ¸µ{¦¡¥i¯à·|¹w¥ý°t¸mÃe¤jªº°}¦C¨Ó¦s©ñµ²ºc¸ê®Æ (³o¼Ë¬O¬°¤FÁקK°õ¦æ¹Lµ{¤¤µo¥Í garbage collect,
¾É­P¹CÀ¸¼È°±)¡C²{¦b method ¥i¥Hª½±µ¥Î°Ñ¦Òªº¤è¦¡¶Ç¦^µ²ºcªº¸ê®Æ¡A©I¥sºÝ¥i¥Hª½±µÅª¨ú»P­×§ï¥¦ªº¤º®e¡C

¦P®É¡A¦³¨Ç·f°t­­¨î¨Ó½T«O³o¼Ë°µ¬O¦w¥þªº:

§A¥u¯à¶Ç¦^ "¯à°÷¦w¥þ¶Ç¦^" ªº°Ñ¦Ò: ¤@­Ó¬O¥~¬É¶Ç»¼µ¹§Aªº°Ñ¦Ò¡A¥t¤@­Ó¬O«ü¦V¥Ø«eª«¥óªº fields (Äæ¦ì) ªº°Ñ¦Ò¡C
ref locals ¦bªì©l¤Æ®É·|³Q«ü¦V¬Y­ÓÀx¦s¦ì¸m¡A¤@¥¹«ü¬£¤§«áµLªk¦A§ó§ï¡C

«D¦P¨Bªº¶Ç¦^«¬§O
¨ì¥Ø«e¬°¤î¡AC# ªº«D¦P¨B method ­­©w¥²¶·¶Ç¦^ void, Task ©Î¬O Task<T> ³o´XºØ«¬§O¡CC# 7.0 ¶}©l¡A¤]¤¹³\§A¥Î¦P¼Ëªº¤è¦¡¡A±q«D¦P¨B¤èªk¶Ç¦^§A©w¸qªº¨ä¥L«¬§O¡C

Á|¨Ò¨Ó»¡¡A§Ú­Ì²{¦b¥i¥H©w¸q ValueTask<T> ³o­Ó struct «¬§O·í§@¶Ç¦^­È¡C
³o¥i¥HÁקK·í«D¦P¨B°õ¦æªºµ²ªG¤w¸g¥i¥Î¡A¦ý¬O«o¦]¬°­n¶i¦æ Task<T> ªº°t¸m¡A¦Ó¾É­P«D¦P¨B°õ¦æªºµ²ªGÁÙ¦bµ¥«Ý¤¤ (awaiting ª¬ºA)¡C³\¦h¯A¤Î buffering(½w½Ä) ªº«D¦P¨B¾Þ§@®É¡A³o°µªk¥i¥H©úÅã¦a­°§C°t¸mªº¦¸¼Æ¡A¦P®É¯à±a¨Ó©úÅ㪺®Ä¯à´£¤É¡C

Ķµù: ¨Ò¦p«D¦P¨B I/O ªº¾Þ§@¡A§Ú­Ì·|¥Î«D¦P¨Bªº¤è¦¡±NÀɮתº¤º®eŪ¨ì buffer ¤º¡A§¹¦¨«á¦A¤£Â_­«½Æ¦P¼Ë°Ê§@¡Aª½¨ìÀÉ®×Ū¨ú§¹²¦¬°¤î¡A³o­Ó°Ê§@¤]³\·|³Q­«½Æ¤W¤d¸U¦¸¡C¦¹®É¥Ñ Task<T> ´À´«¬° ValueTask<T> ¥i¯à¥i¥H±a¨Ó©úÅ㪺®Ä¯à´£¤É¡C

¤]¦³«Ü¦h¨ä¥Lªº±¡ªp¤U¡A§A¥i¥H·Q¹³¦Û­q "task-like" ªºÀ³¥ÎÃþ«¬·|«Ü¦³¥Î¡C­n¥¿½T¦a«Ø¥ß¥¦­Ì¨Ã¤£¬O¨º»òªºª½Æ[¡A©Ò¥H§Ú­Ì¤]¤£´Á«Ý¤j³¡¤Àªº¤H¯à¥¿½Tªº¨Ï¥Î¥¦­Ì¡C¦ý¬O¥¦­Ì¥i¯à¶}©l·|¥X²{¦b¨ä¥Lªº®Ø¬[©Î¬O API¡A¦Ó©I¥sªÌ¥i¥H¹³¹L¥h¨Ï¥Î Task ¤@¼Ëªº¨Ï¥Î¥L¡A¶Ç¦^­È»P await µ¥«Ýµ²ªG¡C

§ó¼sªxªº expression bodies ¦¨­û
¦b C# 6.0 ¥H«e¡Aexpression bodied methods, properties(ÄÝ©Ê) µ¥¥\¯à¤j¨üÅwªï¡A¦ý¤£¬O©Ò¦³ªº¦¨­û³£¥i¥H
¨Ï¥Î¡C¦b C# 7.0 ¤¤¡Aaccessors (¦s¨ú¤l), constructor («Øºc¦¡) »P finalizers (²×µ²¾¹) ³£¤w¥[¨ì¥i¥H¨Ï¥Î expression bodies ªº²M³æ¤¤:

class Person
{
    private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int, string>();
    private int id = GetId();

    public Person(string name) => names.TryAdd(id, name); // constructors
    ~Person() => names.TryRemove(id, out *);              // destructors
    public string Name
    {
        get => names[id];                                 // getters
        set => names[id] = value;                         // setters
    }
}
³o­Ó·s»yªkªº½d¨Òµ{¦¡¨Ã«D¨Ó¦Û Microsoft C# ½sĶ¾¹ªº¹Î¶¤¡A¦Ó¬O¥ÑªÀ¸s¦¨­û°^Ämªº¡C¤Ó´Î¤F! Open source!

Throw ¹Bºâ¦¡
­n¦b¹Bºâ¦¡¤§¤¤¥á¥X¤@­Ó¨Ò¥~ (exception) ¬O«Ü®e©öªº¡A¥u­n©I¥s method (¦b method ¤ºÂY¥X exception) ´N¥i¥H¤F¡C¦ý¬O¦b C# 7.0 §Ú­Ì¤¹³\¦b¹Bºâ¦¡¤§¤¤ª½±µ´N¦a¥á¥X exception:

class Person
{
    public string Name { get; }
    public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(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();
}

&#127775; §ó¦h³Ì·s¤å³¹¤Î¸ê°T >> MSDN ¥xÆW¯»µ·±M­¶ & MSDN ¥xÆW³¡¸¨®æ

        ÀR«ä¦Û¦b : ¡i®É¶¡¦¨´N¤@¤Á¡j®É¶¡¥i¥H³y´N¤H®æ¡A¥i¥H¦¨´N¨Æ·~¡A¤]¥i¥HÀx¿n¥\¼w¡C
ªð¦^¦Cªí ¤W¤@¥DÃD