C# 6.0 新增和增強的功能【基礎篇】

2022-10-25 21:03:21

C# 6.0 是在 visual studio 2015 中引入的。此版本更多關注了語法的改進,讓程式碼更簡潔且更具可讀性,使程式設計更有效率,而不是和前幾個版本一樣增加主導性的功能。

一、靜態匯入

我們都知道,靜態類中的方法是直接通過類名參照的。

例如:(Math 是系統自帶的靜態類,在程式中可以直接參照)

var num = Math.Sqrt(3*3 + 4*4);//取給定值的平方根

新寫法:(分兩步)

using static System.Console;
using static System.Math;// 1/2 在名稱空間中,統一參照靜態類

namespace Test.Test.ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine(Sqrt(3*3 + 4*4));// 2/2 直接呼叫方法,不用再帶靜態類名
        }
    }
}

using static 指令命名了一種型別,無需指定型別名稱即可存取其靜態成員和巢狀型別。

using static 僅匯入可存取的靜態成員和指定型別中宣告的巢狀型別。 不匯入繼承的成員。

 二、異常篩選器

從 C# 6 開始,when 可用於 catch 語句中,以指定為執行特定例外處理程式而必須為 true 的條件。 語法為:

catch (ExceptionType [e]) when (expr)

 其中,expr 是一個表示式,其計算結果為布林值。 如果該表示式返回 true,則執行例外處理程式;如果返回 false,則不執行。

具體用法範例:

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;
        }
    }
}

 三、自動屬性初始化表示式

當需要將屬性初始化為其型別預設值以外的值時,C# 通過在屬性的右括號後設定值達到此目的。

對於 FirstName 屬性的初始值,需要設定為空字串而非 null。 可按如下所示進行指定:

public class Person
{
    public string FirstName { get; set; } = string.Empty;
}

或者自行定義儲存:

public class Person
{
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
    private string _firstName;
}

 四、Expression bodied 成員(表示式主體定義 =>)

 expression-bodied 方法包含單個表示式,它返回的值的型別與方法的返回型別匹配;或者,對於返回 void 的方法,其表示式則執行某些操作。常規語法:

member => expression;

例如,替代 ToString 方法的型別通常包含單個表示式,該表示式返回當前物件的字串表示形式。

下面的範例定義 Person 類,該類通過表示式主體定義替代 ToString。 它還定義向控制檯顯示名稱的 DisplayName 方法。

請注意,ToString 表示式主體定義中未使用 return 關鍵字。

using System;

public class Person
{
   public Person(string firstName, string lastName)
   {
      fname = firstName;
      lname = lastName;
   }

   private string fname;
   private string lname;

   public override string ToString() => $"{fname} {lname}".Trim();
   public void DisplayName() => Console.WriteLine(ToString());
}

class Example
{
   static void Main()
   {
      Person p = new Person("Mandy", "Dejesus");
      Console.WriteLine(p);
      p.DisplayName();
   }
}

 五、Null 傳播器

僅當運算元的計算結果為非 NULL 時,NULL 條件運運算元才對其運算元應用成員存取 或元素存取 ?. 操作;否則,它會返回 NULL。從而避免了空物件的報錯:Object reference not set to an instance of an object。

NULL 條件運運算元採用最小化求值策略。 也就是說,如果條件成員或元素存取運算鏈中的一個運算返回 null,則鏈的其餘部分不會執行。

如下範例:

int GetSumOfFirstTwoOrDefault(int[] numbers)
{
    // ??(Null 合併操作符): 如果此運運算元的左運算元不為 null,則此運運算元將返回左運算元,否則返回右運算元
    if ((numbers?.Length ?? 0) < 2)
    {
        return 0;
    }
    return numbers[0] + numbers[1];
}

Console.WriteLine(GetSumOfFirstTwoOrDefault(null));  // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault(new int[0]));  // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault(new[] { 3, 4, 5 }));  // output: 7

六、字串內插($"{}")

$ 特殊字元將字串文字標識為內插字串 。 內插字串是可能包含內插表示式的字串文字 。 將內插字串解析為結果字串時,帶有內插表示式的項會替換為表示式結果的字串表示形式。

要在內插字串生成的文字中包含大括號 "{" 或 "}",請使用兩個大括號,即 "{{" 或 "}}"。

因為冒號(":")在內插表示式項中具有特殊含義,為了在內插表示式中使用條件運運算元,請將表示式放在括號內。

string name = "Horace";
int age = 34;
Console.WriteLine($"He asked, \"Is your name {name}?\", but didn't wait for a reply :-{{");
Console.WriteLine($"{name} is {age} year{(age == 1 ? "" : "s")} old.");
// Expected output is:
// He asked, "Is your name Horace?", but didn't wait for a reply :-{
// Horace is 34 years old.

七、nameof 表示式

nameof 表示式可生成變數、型別或成員的名稱作為字串常數:

Console.WriteLine(nameof(System.Collections.Generic));  // output: Generic
Console.WriteLine(nameof(List<int>));  // output: List
Console.WriteLine(nameof(List<int>.Count));  // output: Count
Console.WriteLine(nameof(List<int>.Add));  // output: Add
var numbers = new List<int> { 1, 2, 3 };
Console.WriteLine(nameof(numbers));  // output: numbers
Console.WriteLine(nameof(numbers.Count));  // output: Count
Console.WriteLine(nameof(numbers.Add));  // output: Add
//在逐字識別符號的情況下,@ 字元不是名稱的一部分,如以下範例所示:
var @new = 5;
Console.WriteLine(nameof(@new));  // output: new

nameof 表示式在編譯時進行求值,在執行時無效。

八、 索引初始化表示式

 從本質來看,[xxx] = yyy 這種語法,xxx 可以是任意型別,凡是有索引器支援的型別,均可以使用這種語法。

private static void Main()
{
    var dictionary = new Dictionary<int, string>
    {
        [1] = "Value1",
        [2] = "Value2",
        [3] = "Value3"
    };
}

 九、Catch/Finally 塊中的 Await

 Asyn 方法是一個現在很常用的方法,當使用 async 和 await 時,你或許曾有這樣的經歷,就是你想要在 catch 塊或 finally 塊中使用它們,比如當出現一個 exception 而你希望將紀錄檔記在檔案或者呼叫一個服務將 exception 資訊傳送給 server,而這些操作可能很耗時。這種情況下,在 catch 塊中的非同步方法中使用 await 將會很有幫助。具體語法範例:

public async Task SubmitDataToServer()
{
    try
    {
    }
    catch
    {
        await LogExceptionAsync();
    }
    finally
    {
        await CloseConnectionAsync();
    }
}

 注:暫時整理這些,歡迎指正和補充。