C#7.0的新特性有哪些-創(chuàng)新互聯(lián)

這篇文章主要介紹了C#7.0的新特性有哪些,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、網(wǎng)站設(shè)計、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的柘城網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

表達式 everywhere

C# 6.0 中,可以對成員方法和只讀屬性使用 Lambda 表達式,當(dāng)時最郁悶的就是為什么不支持屬性的 set 訪問器?,F(xiàn)在好了,不僅 set 方法器支持使用 Lambda 表達式,構(gòu)造方法、析構(gòu)方法以及索引都支持以 Lambda 表達式方式定義了。

class SomeModel
{
    private string internalValue;

    public string Value
    {
        get => internalValue;
        set => internalValue = string.IsNullOrWhiteSpace(value) ? null : value;
    }
}

out 變量

out 變量是之前就存在的語法,C# 7.0 只是允許它將申明和使用放在一起,避免多一行代碼。最直接的效果,就是可以將兩個語句用一個表達式完成。這里以一個簡化版的 Key 類為例,這個類早期被我們用于處理通過 HTTP Get/Post 傳入的 ID 值。

public class Key
{
    public string Value { get; }

    public Key(string key)
    {
        Value = key;
    }

    public int IntValue
    {
        get
        {
            // C# 6.0,需要提前定義 intValue,但不需要初始化
            // 雖然 C# 6.0 可以為只讀屬性使用 Lambda 表達式
            // 但這里無法用一個表達式表達出來
            int intValue;
            return int.TryParse(Value, out intValue) ? intValue : 0;
        }
    }
}

而在 C# 7 中就簡單了

// 注意 out var intValue,
// 對于可推導(dǎo)的類型甚至可以用 var 來申明變量
public int IntValue => int.TryParse(Value, out var intValue) ? intValue : 0;

元組和解構(gòu)

用過 System.Tuple 的朋友一定對其 Item1Item2 這樣毫無語義的命名深感不爽。不過 C# 7.0 帶來了語義化的命名,同時,還減化了元組的創(chuàng)建,不再需要 Tuple.Create(...)。另外,要使用新的元組特性和解構(gòu),需要引入 NuGet 包 System.ValueTuple。

Install-Package System.ValueTuple

當(dāng)然,元組常用于返回多個值的方法。也有些人喜歡用 out 參數(shù)來返回,但即使現(xiàn)在可以 out 變量,我仍然不贊成廣泛使用 out 參數(shù)。

下面這個示例方法用于返回一個默認(rèn)的時間范圍(從今天開始算往前一共 7 天),用于數(shù)據(jù)檢索。

// 返回類型是一個包含兩個元素的元組
(DateTime Begin, DateTime End) GetDefaultDateRange()
{
    var end = DateTime.Today.AddDays(1);
    var begin = end.AddDays(-7);

    // 這里使用一對圓括號就創(chuàng)建了一個元組
    return (begin, end);
}

調(diào)用這個方法可以獲得元組,因為定義的時候返回值指定了每個數(shù)據(jù)成員的名稱,所以從元組獲取數(shù)據(jù)可以是語義化的,當(dāng)然仍然可以使用 Item1Item2。

var range = GetDefaultDateRange();
var begin = range.Begin;    // 也可以 begin = range.Item1
var end = range.End;        // 也可以 end = range.Item2

上面這個例子還可以簡化,不用 range 這個中間變量,這就用到了解構(gòu)

var (begin, end) = GetDefaultDateRange();

這里創(chuàng)建元組是以返回值來舉例的,其實它就是一個表達式,可以在任何地方創(chuàng)建元組。上面的例子邏輯很簡單,可以用表達式解決。下面的示例順便演示了非語義化的返回類型申明。

// 原來的 (DateTime Begin, DateTime End) 申明也是沒問題的
(DateTime, DateTime) GetDefaultDateRange()
    => (DateTime.Today.AddDays(1).AddDays(-7), DateTime.Today.AddDays(1));

解構(gòu)方法 Deconstrct

解構(gòu)方法可以讓任何類(而不僅僅是元組)按定義的參數(shù)進行解構(gòu)。而且神奇的是解構(gòu)方法可以是成員方法,也可以定義成擴展方法。

public class Size
{
    public int Width { get; }
    public int Height { get; }
    public int Tall { get; }

    public Size(int width, int height, int tall)
    {
        this.Width = width;
        this.Height = height;
        this.Tall = tall;
    }

    // 定義成成員方法的解構(gòu)
    public void Deconstruct(out int width, out int height)
    {
        width = Width;
        height = Height;
    }
}

public static class SizeExt
{
    // 定義成擴展方法的解構(gòu)
    public static void Deconstruct(this Size size, out int width, out int height, out int tall)
    {
        width = size.Width;
        height = size.Height;
        tall = size.Tall;
    }
}

下面是使用解構(gòu)的代碼

var size = new Size(1920, 1080, 10);
var (w, h) = size;
var (x, y, z) = size;

改造 Size 的構(gòu)造方法

還記得前面提到的構(gòu)造方法可以定義為 Lambda 表達式嗎?下面是使用元組和 Lambda 對 Size 構(gòu)造方法的改造——我已經(jīng)醉了!

public Size(int width, int height, int tall)
    => (Width, Height, Tall) = (width, height, tall);

模式匹配

模式匹配目前支持 isswitch。說起來挺高大上的一個名字,換個接地氣一點的說法就是判斷類型順便定義個具體類型的引用,有興趣還可以加再點額外的判斷。

對于 is 來說,就是判斷的時候順便定義個變量再初始化一下,所以像原來這樣寫的代碼

// 假設(shè)邏輯能保證這里的 v 可能是 string 也 可能是 int
string ToString(object v) {
    if (v is int) {
        int n = (int) v;
        return n.ToString("X4");
    } else {
        return (string) n;
    }
}

可以簡化成——好吧,直接一步到位寫成表達式好了

string ToString(object v)
    => (v is int n) ? n.ToString("X4") : (string) v;

當(dāng)然你可能說之前的那個也可以簡化成一個表達式——好吧,不深究這個問題好嗎?我只是演示 is 的模式匹配而已。

switch 中的模式匹配似乎要有用得多,還是以 ToString 為例吧

static string ToString(object v)
{
    switch (v)
    {
        case int n when n > 0xffff:
            // 判斷類型,匹配的情況下再對值進行一個判斷
            return n.ToString("X8");
        case int n:
            // 判斷類型,這里 n 肯定 <= 0xffff
            return n.ToString("X4");
        case bool b:
            return b ? "ON" : "OFF";
        case null:
            return null;
        default:
            return v.ToString();
    }
}

注意一下上面第一個分支中 when 的用法就好了。

ref 局部變量和 ref 返回值

這已經(jīng)是很接近 C/C++ 的一種用法了。雖然官方說法是這樣做可以解決一些安全性問題,但我個人目前還是沒遇到它的使用場景。如果設(shè)計足夠好,在目前又加入了元組新特性和解構(gòu)的情況下,個人認(rèn)為幾乎可以避免使用 outref

既然沒用到,我也不多說了,有用到的同學(xué)來討論一下!

數(shù)字字面量語法增強

這里有兩點增強,一點是引入了 0b 前綴的二進制數(shù)字面量語法,另一點是可以在數(shù)值字面量中任意使用 _ 對數(shù)字進行分組。這個不用多數(shù),舉兩個例就明白了

const int MARK_THREE = 0b11;            // 0x03
const int LONG_MARK = 0b_1111_1111;     // 0xff
const double PI = 3.14_1592_6536

局部函數(shù)

經(jīng)常寫 JavaScript 的同學(xué)肯定會深有體會,局部函數(shù)是個好東西。當(dāng)然它在 C# 中帶來的大好處是將某些代碼組織在了一起。我之前在項目中大量使用了 Lambda 來代替局部函數(shù),現(xiàn)在可以直接替換成局部函數(shù)了。Labmda 和局部函數(shù)雖然多數(shù)情況下能做同樣的事情,但是它們?nèi)匀挥幸恍﹨^(qū)別

  • 對于 Lambda,編譯器要干的事情比較多??傊?,就是編譯效率要低得多

  • Lambda 通過委托實現(xiàn),調(diào)用過程比較復(fù)雜,局部函數(shù)可以直接調(diào)用。簡單地說就是局部函數(shù)執(zhí)行效率更高

  • Lambda 必須先定義再使用,局部函數(shù)可以定義在使用之后。據(jù)說這在對遞歸算法的支持上會有區(qū)別

比較常用的地方是 Enumerator 函數(shù)和 async 函數(shù)中,因為它們實際都不是立即執(zhí)行的。

我在項目中多是用來組織代碼。局部函數(shù)代替只被某一個公共 API 調(diào)用的私有函數(shù)來組織代碼雖然不失為一個簡化類結(jié)構(gòu)的好方法,但是把公共 API 函數(shù)的函數(shù)體拉長。所以很多時候我也會使用內(nèi)部類來代替某些私有函數(shù)來組織代碼。這里順便說一句,我不贊成使用 #region 組織代碼。

支持更多 async 返回類型

如果和 JavaScript 中 ES2017 的 async 相比,C# 中的 Task/Task<T> 就比較像 Promise 的角色。不用羨慕 JavaScript 的 async 支持 Promise like,現(xiàn)在 C# 的 async 也支持 Task like 了,只要實現(xiàn)了 GetAwaiter 方法就行。

官方提供了一個 ValueTask 作為示例,可以通過 NuGet 引入:

Install-Package System.Threading.Tasks.Extensions

這個 ValueTask 比較有用的一點就是兼容了數(shù)據(jù)類型和 Task:

string cache;

ValueTask<string> GetData()
{
    return cache == null ? new ValueTask<string>(cache) : new ValueTask<string>(GetRemoteData());

    // 局部函數(shù)
    async Task<string> GetRemoteData()
    {
        await Task.Delay(100);
        return "hello async";
    }
}

《〔譯〕 C# 7 的新特性》花了很大的篇幅來介紹 C# 7.0 的 9 個新特性,這里我根據(jù)項目經(jīng)驗,通過實例對它們進行一個快速的介紹,讓大家能在短時間內(nèi)了解它們。

總的來說,這些新特性使 C# 7.0 更容易以函數(shù)式編程的思想來寫代碼,C# 6.0 在這條路上已經(jīng)做了不少工作, C# 7.0 更近一步!

表達式 everywhere

C# 6.0 中,可以對成員方法和只讀屬性使用 Lambda 表達式,當(dāng)時最郁悶的就是為什么不支持屬性的 set 訪問器?,F(xiàn)在好了,不僅 set 方法器支持使用 Lambda 表達式,構(gòu)造方法、析構(gòu)方法以及索引都支持以 Lambda 表達式方式定義了。

class SomeModel
{
    private string internalValue;

    public string Value
    {
        get => internalValue;
        set => internalValue = string.IsNullOrWhiteSpace(value) ? null : value;
    }
}

out 變量

out 變量是之前就存在的語法,C# 7.0 只是允許它將申明和使用放在一起,避免多一行代碼。最直接的效果,就是可以將兩個語句用一個表達式完成。這里以一個簡化版的 Key 類為例,這個類早期被我們用于處理通過 HTTP Get/Post 傳入的 ID 值。

public class Key
{
    public string Value { get; }

    public Key(string key)
    {
        Value = key;
    }

    public int IntValue
    {
        get
        {
            // C# 6.0,需要提前定義 intValue,但不需要初始化
            // 雖然 C# 6.0 可以為只讀屬性使用 Lambda 表達式
            // 但這里無法用一個表達式表達出來
            int intValue;
            return int.TryParse(Value, out intValue) ? intValue : 0;
        }
    }
}

而在 C# 7 中就簡單了

// 注意 out var intValue,
// 對于可推導(dǎo)的類型甚至可以用 var 來申明變量
public int IntValue => int.TryParse(Value, out var intValue) ? intValue : 0;

元組和解構(gòu)

用過 System.Tuple 的朋友一定對其 Item1、Item2 這樣毫無語義的命名深感不爽。不過 C# 7.0 帶來了語義化的命名,同時,還減化了元組的創(chuàng)建,不再需要 Tuple.Create(...)。另外,要使用新的元組特性和解構(gòu),需要引入 NuGet 包 System.ValueTuple。

Install-Package System.ValueTuple

當(dāng)然,元組常用于返回多個值的方法。也有些人喜歡用 out 參數(shù)來返回,但即使現(xiàn)在可以 out 變量,我仍然不贊成廣泛使用 out 參數(shù)。

下面這個示例方法用于返回一個默認(rèn)的時間范圍(從今天開始算往前一共 7 天),用于數(shù)據(jù)檢索。

// 返回類型是一個包含兩個元素的元組
(DateTime Begin, DateTime End) GetDefaultDateRange()
{
    var end = DateTime.Today.AddDays(1);
    var begin = end.AddDays(-7);

    // 這里使用一對圓括號就創(chuàng)建了一個元組
    return (begin, end);
}

調(diào)用這個方法可以獲得元組,因為定義的時候返回值指定了每個數(shù)據(jù)成員的名稱,所以從元組獲取數(shù)據(jù)可以是語義化的,當(dāng)然仍然可以使用 Item1Item2。

var range = GetDefaultDateRange();
var begin = range.Begin;    // 也可以 begin = range.Item1
var end = range.End;        // 也可以 end = range.Item2

上面這個例子還可以簡化,不用 range 這個中間變量,這就用到了解構(gòu)

var (begin, end) = GetDefaultDateRange();

這里創(chuàng)建元組是以返回值來舉例的,其實它就是一個表達式,可以在任何地方創(chuàng)建元組。上面的例子邏輯很簡單,可以用表達式解決。下面的示例順便演示了非語義化的返回類型申明。

// 原來的 (DateTime Begin, DateTime End) 申明也是沒問題的
(DateTime, DateTime) GetDefaultDateRange()
    => (DateTime.Today.AddDays(1).AddDays(-7), DateTime.Today.AddDays(1));

解構(gòu)方法 Deconstrct

解構(gòu)方法可以讓任何類(而不僅僅是元組)按定義的參數(shù)進行解構(gòu)。而且神奇的是解構(gòu)方法可以是成員方法,也可以定義成擴展方法。

public class Size
{
    public int Width { get; }
    public int Height { get; }
    public int Tall { get; }

    public Size(int width, int height, int tall)
    {
        this.Width = width;
        this.Height = height;
        this.Tall = tall;
    }

    // 定義成成員方法的解構(gòu)
    public void Deconstruct(out int width, out int height)
    {
        width = Width;
        height = Height;
    }
}

public static class SizeExt
{
    // 定義成擴展方法的解構(gòu)
    public static void Deconstruct(this Size size, out int width, out int height, out int tall)
    {
        width = size.Width;
        height = size.Height;
        tall = size.Tall;
    }
}

下面是使用解構(gòu)的代碼

var size = new Size(1920, 1080, 10);
var (w, h) = size;
var (x, y, z) = size;

改造 Size 的構(gòu)造方法

還記得前面提到的構(gòu)造方法可以定義為 Lambda 表達式嗎?下面是使用元組和 Lambda 對 Size 構(gòu)造方法的改造——我已經(jīng)醉了!

public Size(int width, int height, int tall)
    => (Width, Height, Tall) = (width, height, tall);

模式匹配

模式匹配目前支持 isswitch。說起來挺高大上的一個名字,換個接地氣一點的說法就是判斷類型順便定義個具體類型的引用,有興趣還可以加再點額外的判斷。

對于 is 來說,就是判斷的時候順便定義個變量再初始化一下,所以像原來這樣寫的代碼

// 假設(shè)邏輯能保證這里的 v 可能是 string 也 可能是 int
string ToString(object v) {
    if (v is int) {
        int n = (int) v;
        return n.ToString("X4");
    } else {
        return (string) n;
    }
}

可以簡化成——好吧,直接一步到位寫成表達式好了

string ToString(object v)
    => (v is int n) ? n.ToString("X4") : (string) v;

當(dāng)然你可能說之前的那個也可以簡化成一個表達式——好吧,不深究這個問題好嗎?我只是演示 is 的模式匹配而已。

switch 中的模式匹配似乎要有用得多,還是以 ToString 為例吧

static string ToString(object v)
{
    switch (v)
    {
        case int n when n > 0xffff:
            // 判斷類型,匹配的情況下再對值進行一個判斷
            return n.ToString("X8");
        case int n:
            // 判斷類型,這里 n 肯定 <= 0xffff
            return n.ToString("X4");
        case bool b:
            return b ? "ON" : "OFF";
        case null:
            return null;
        default:
            return v.ToString();
    }
}

注意一下上面第一個分支中 when 的用法就好了。

ref 局部變量和 ref 返回值

這已經(jīng)是很接近 C/C++ 的一種用法了。雖然官方說法是這樣做可以解決一些安全性問題,但我個人目前還是沒遇到它的使用場景。如果設(shè)計足夠好,在目前又加入了元組新特性和解構(gòu)的情況下,個人認(rèn)為幾乎可以避免使用 outref

既然沒用到,我也不多說了,有用到的同學(xué)來討論一下!

數(shù)字字面量語法增強

這里有兩點增強,一點是引入了 0b 前綴的二進制數(shù)字面量語法,另一點是可以在數(shù)值字面量中任意使用 _ 對數(shù)字進行分組。這個不用多數(shù),舉兩個例就明白了

const int MARK_THREE = 0b11;            // 0x03
const int LONG_MARK = 0b_1111_1111;     // 0xff
const double PI = 3.14_1592_6536

局部函數(shù)

經(jīng)常寫 JavaScript 的同學(xué)肯定會深有體會,局部函數(shù)是個好東西。當(dāng)然它在 C# 中帶來的大好處是將某些代碼組織在了一起。我之前在項目中大量使用了 Lambda 來代替局部函數(shù),現(xiàn)在可以直接替換成局部函數(shù)了。Labmda 和局部函數(shù)雖然多數(shù)情況下能做同樣的事情,但是它們?nèi)匀挥幸恍﹨^(qū)別

  • 對于 Lambda,編譯器要干的事情比較多。總之呢,就是編譯效率要低得多

  • Lambda 通過委托實現(xiàn),調(diào)用過程比較復(fù)雜,局部函數(shù)可以直接調(diào)用。簡單地說就是局部函數(shù)執(zhí)行效率更高

  • Lambda 必須先定義再使用,局部函數(shù)可以定義在使用之后。據(jù)說這在對遞歸算法的支持上會有區(qū)別

比較常用的地方是 Enumerator 函數(shù)和 async 函數(shù)中,因為它們實際都不是立即執(zhí)行的。

我在項目中多是用來組織代碼。局部函數(shù)代替只被某一個公共 API 調(diào)用的私有函數(shù)來組織代碼雖然不失為一個簡化類結(jié)構(gòu)的好方法,但是把公共 API 函數(shù)的函數(shù)體拉長。所以很多時候我也會使用內(nèi)部類來代替某些私有函數(shù)來組織代碼。這里順便說一句,我不贊成使用 #region 組織代碼。

支持更多 async 返回類型

如果和 JavaScript 中 ES2017 的 async 相比,C# 中的 Task/Task<T> 就比較像 Promise 的角色。不用羨慕 JavaScript 的 async 支持 Promise like,現(xiàn)在 C# 的 async 也支持 Task like 了,只要實現(xiàn)了 GetAwaiter 方法就行。

官方提供了一個 ValueTask 作為示例,可以通過 NuGet 引入:

Install-Package System.Threading.Tasks.Extensions

這個 ValueTask 比較有用的一點就是兼容了數(shù)據(jù)類型和 Task:

string cache;

ValueTask<string> GetData()
{
    return cache == null ? new ValueTask<string>(cache) : new ValueTask<string>(GetRemoteData());

    // 局部函數(shù)
    async Task<string> GetRemoteData()
    {
        await Task.Delay(100);
        return "hello async";
    }
}

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“C#7.0的新特性有哪些”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計公司,關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計公司行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、網(wǎng)站設(shè)計器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

網(wǎng)頁題目:C#7.0的新特性有哪些-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://bm7419.com/article46/ddpoeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、網(wǎng)站制作Google網(wǎng)站設(shè)計公司、微信小程序、微信公眾號

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)