1. C# 9.0 新特性預(yù)覽 - init-only 屬性

        共 2026字,需瀏覽 5分鐘

         ·

        2020-10-30 04:39

        前言

        隨著 .NET 5 發(fā)布日期的日益臨近,其對(duì)應(yīng)的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語(yǔ)法糖)也已基本鎖定,本系列文章將向大家展示它們。

        目錄

        [C# 9.0 新特性預(yù)覽 - 類(lèi)型推導(dǎo)的 new]
        [C# 9.0 新特性預(yù)覽 - 空參數(shù)校驗(yàn)]
        [C# 9.0 新特性預(yù)覽 - 頂級(jí)語(yǔ)句]
        [C# 9.0 新特性預(yù)覽 - init-only 屬性]
        [C# 9.0 新特性預(yù)覽 - Record 類(lèi)型]
        [C# 9.0 新特性預(yù)覽 - 模式匹配的改善]
        [C# 9.0 新特性預(yù)覽 - 源代碼生成器]
        [C# 9.0 新特性預(yù)覽 - 其他小的變化]

        只初始化 setter (Init Only Setters)

        這個(gè)特性允許創(chuàng)建只初始化(init only)的屬性和索引器,使得 C# 中的不可變模型更加靈活。

        背景

        在此之前,我們創(chuàng)建實(shí)體類(lèi)/POCO類(lèi)/DTO類(lèi)等等模型類(lèi)的時(shí)候,都期望屬性只讀不允許從外部修改,會(huì)將屬性的 setter 設(shè)為私有或者干脆不設(shè)置 setter,例如:

        public class Person
        {
        public string Name { get; private set; }
        // OR
        //public string Name { get; }
        }

        再添加一個(gè)擁有全部屬性作為簽名的構(gòu)造方法:

        ...
        public Person(string name)
        {
        this.Name = name;
        }
        ...

        這樣做雖然可以達(dá)到目的,但是帶來(lái)了兩個(gè)問(wèn)題
        1.假如屬性增多,會(huì)帶來(lái)工作量的成倍增加,以及不易維護(hù)
        2.無(wú)法使用對(duì)象初始化器(object initializers)

        var person = new Person
        {
        Name = "Rwing" // Compile Error
        };

        在這個(gè)情況下,init 關(guān)鍵字應(yīng)運(yùn)而生了。

        語(yǔ)法

        語(yǔ)法很簡(jiǎn)單,只需要將屬性中的 set 關(guān)鍵字替換為 init 即可:

        public string Name { get; init; }

        以上代碼會(huì)被大致翻譯為:

        private readonly string _name;
        public string Name
        {
        get { return _name; }
        set { _name = value;}
        }

        可以看到,與 set 的區(qū)別是,init 會(huì)為背后的字段添加 readonly 關(guān)鍵字。
        這樣我們就可以去掉一堆屬性的構(gòu)造方法轉(zhuǎn)而使用對(duì)象初始化器了,并且達(dá)到了不可變的目的。

        var person = new Person
        {
        Name = "Rwing"
        };
        // 初始化后無(wú)法再次修改
        person.Name = "Foo"; // Error: Name is not settable

        這一語(yǔ)法,有很多場(chǎng)景需要配合同樣在 C# 9.0 中新增的 record 類(lèi)型使用。

        哪些情況下可以被設(shè)置

        • 通過(guò)對(duì)象初始化器

        • 通過(guò) with 表達(dá)式

        • 在自身或者派生類(lèi)的構(gòu)造方法中

        • 在標(biāo)記為 init 的屬性中

        • 在特性(attribute)類(lèi)的命名參數(shù)屬性中

        以上場(chǎng)景不難理解,但是值得一提的是,只有 get 的屬性是不可以派生類(lèi)的構(gòu)造方法中賦值的,但是 init 可以:

        class Base
        {
        public bool Foo { get; init; }
        public bool Bar { get; }
        }

        class Derived : Base
        {
        Derived()
        {
        Foo = true;
        Bar = true; // ERROR
        }
        }

        此外有一種例外, 在以上場(chǎng)景中的 lambda 或本地函數(shù)中,也不允許被設(shè)置,例如:
        原因也很簡(jiǎn)單,lambda 或本地函數(shù)在編譯后已經(jīng)不在構(gòu)造函數(shù)中了。

        public class Class
        {
        public string Property { get; init; }

        Class()
        {
        System.Action a = () =>
        {
        Property = null; // ERROR
        };
        local();
        void local()
        {
        Property = null; // ERROR
        }
        }
        }

        參考

        [Proposal: Init Only Setters]
        [InitOnlyMemberTests.cs]


        瀏覽 36
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 激情床戏动态图 | 男人的天堂色一色 | 天天爱天天操天天干 | 男女在线视频 | 性感美女艹逼 |