洪流學(xué)堂熏版,讓你快人幾步!本文首發(fā)于洪流學(xué)堂微信公眾號捍掺。
本文是該系列《Unity腳本運(yùn)行時更新帶來了什么撼短?》的第8篇。
洪流學(xué)堂公眾號回復(fù)runtime
挺勿,獲取本系列所有文章曲横。
Unity2017-2018.2中的4.x運(yùn)行時已經(jīng)支持到C#6,之前的文章已經(jīng)介紹完畢。Unity2018.3將支持到C# 7.3禾嫉,今天我們來看看C#7.3新特性能給代碼帶來什么吧灾杰,不過這些特性得等到Unity2018.3才可以用哦。
C#7.3 新特性
通過一個相對較小的版本熙参,C# 7.3解決了一些自C# 1和2以來長期懸而未決的問題艳吠。
重載解析
從C# 1.0開始,重載解析規(guī)則的設(shè)計就相當(dāng)有問題孽椰。在某些情況下讲竿,它會選兩個或更多方法作為候選,雖然所有這些方法中只有一個會被使用弄屡。根據(jù)這些錯誤選出的方法的優(yōu)先級,編輯器要么會報沒有匹配的方法鞋诗,要么會報匹配不明確膀捷。
C# 7.3把其中部分檢查移到了重載解析期間,而不是重載解析之后削彬,這樣全庸,錯誤的匹配就不會導(dǎo)致編譯器錯誤。改進(jìn)后的重載候選提案概括了這些檢查:
- 當(dāng)一個方法組既包含實例又包含靜態(tài)成員時融痛,如果調(diào)用時沒有實例接收者或上下文壶笼,我們就會丟棄實例成員,如果調(diào)用時有實例接收者雁刷,我們就丟棄靜態(tài)成員覆劈。當(dāng)沒有接收者時,我們只會在一個靜態(tài)上下文中包含靜態(tài)成員沛励,否則會同時包含靜態(tài)和實例成員责语。當(dāng)不確定接收者是實例還是類型時,我們會兩者都包含目派。在靜態(tài)上下文中坤候,不能使用隱式的this實例接收者,它包含的方法體中沒有定義this企蹭,如靜態(tài)成員白筹,它還包含不能使用this的地方,如字段初始化器和構(gòu)造函數(shù)初始化器谅摄。
- 當(dāng)方法組包含一些泛型方法徒河,而它們的類型參數(shù)不滿足約束時,這些成員會被從候選集中移除送漠。
- 對于方法組轉(zhuǎn)換虚青,那些返回類型與委托的返回類型不一致的候選方法會被從候選集中移除。
泛型約束:枚舉螺男、委托和非托管
自C# 2.0引入泛型以來棒厘,開發(fā)人員就一直在抱怨纵穿,無法把一個泛型類型指定為枚舉。這個問題終于解決了奢人,你現(xiàn)在可以使用enum關(guān)鍵字作為泛型約束了谓媒。同樣,你現(xiàn)在可以使用delegate關(guān)鍵字作為泛型約束了何乎。
這些關(guān)鍵字可能并不是和你預(yù)期的那樣發(fā)揮作用句惯。如果約束是T : enum,那么有人可能就會使用Foo支救,而你的意思也許是讓他們使用System.Enum的子類抢野。盡管如此,這應(yīng)該可以覆蓋枚舉和委托的大多數(shù)使用場景各墨。
非托管類型約束提案使用了unmanaged關(guān)鍵字指孤,用于說明泛型類型必須是“非引用類型,并且在任意嵌套層次上都不包含引用類型字段贬堵∈研”這是為了用在底層交互代碼中,當(dāng)你需要“創(chuàng)建可供所有非托管類型重用的例程時”黎做。非托管類型包括:
- 基元類型sbyte叉跛、byte、short蒸殿、ushort筷厘、int、uint宏所、long敞掘、ulong、char楣铁、float玖雁、double、decimal盖腕、bool赫冬、IntPtr或UIntPtr;
- 任何枚舉類型溃列;
- 指針類型劲厌;
- 只包含上述類型的用戶定義結(jié)構(gòu)。
隱藏字段的Attribute
雖然自實現(xiàn)的Property非常有用听隐,但是它們有一些局限补鼻,Attribute不適用于后備字段,因為你看不到它。雖然通常來說這不是問題风范,但在處理序列化時就可能有問題了咨跌。
面向自實現(xiàn)Property字段的Attribute提案用一種簡單的方法解決了這個問題。當(dāng)把一個Attribute應(yīng)用到一個自實現(xiàn)的Property時硼婿,只需在字段定義時加上field:修飾符锌半。
[Serializable]
public class Foo {
[field: NonSerialized]
public string MySecret { get; set; }
}
元組比較(==和!=)
雖然提案的名稱“支持元組類型==和!=比較”很好地概括了這項特性,但還有一些細(xì)節(jié)和邊際情況需要注意寇漫。最重要的是潛在的破壞性變化:
如果有人自己編寫了一個ValueTuple類型刊殉,并實現(xiàn)了比較操作符,之前州胳,重載解析會找到它們记焊。但是,新的元組情況出現(xiàn)在重載解析之前栓撞,我們會通過元組比較處理這種情況遍膜,而不是基于用戶定義的比較。
理想情況下腐缤, 這個自定義的ValueTuple類型會遵循與C# 7.3編譯器同樣的規(guī)則,但是肛响,在如何處理嵌套元組和動態(tài)類型方面岭粤,可能會有微妙的差別。
初始化器中的表達(dá)式變量
在某種程度上特笋,這看上去像個反特性剃浇。微軟不僅沒有增加功能,而是去掉了表達(dá)式變量的使用場景限制猎物。
我們移除了在ctor初始化器中不能聲明表達(dá)式變量(out變量聲明和聲明方式)的限制虎囚。這樣聲明的變量其作用域是整個構(gòu)造函數(shù)的函數(shù)體。
我們移除了在字段或Property初始化器中不能聲明表達(dá)式變量(out變量聲明和聲明方式)的限制蔫磨。這樣聲明的變量其作用域是整個初始化表達(dá)式淘讥。
我們移除了在會被翻譯成lambda表達(dá)式主體的查詢表達(dá)式子句中不能聲明表達(dá)式變量(out變量聲明和聲明方式)的限制。這樣聲明的變量其作用域是整個查詢子句表達(dá)式堤如。
最初增加這些限制只是因為“沒有時間”蒲列。也許,這些限制縮短了了C# 7之前版本完工所需的測試時間搀罢。
棧分配數(shù)組
C#中有一個很少使用單相當(dāng)重要的特性蝗岖,就是能夠通過stackalloc關(guān)鍵字在棧上分配數(shù)組。與分配在堆上榔至、會導(dǎo)致GC壓力的普通數(shù)組相比抵赢,這可能會提供更好的性能。
int* block = stackalloc int[3] { 1, 2, 3 };
使用棧分配數(shù)組有點危險。因為它需要持有一個指向棧的指針铅鲤,而且只能用于不安全的上下文中划提。CLR會啟用緩沖區(qū)溢出檢測來緩解這種情況,那會導(dǎo)致“應(yīng)用程序盡快終止”彩匕。
在C# 7.3中腔剂,你可以在創(chuàng)建數(shù)組時對其初始化,就像你對普通數(shù)組所做的那樣驼仪。該提案沒有提供細(xì)節(jié)掸犬,但微軟正考慮預(yù)初始化一個主數(shù)組,當(dāng)函數(shù)被調(diào)用時可以快速復(fù)制绪爸。理論上講湾碎,這比創(chuàng)建一個數(shù)組然后一個元素一個元素的初始化要快。
注意奠货,棧分配數(shù)組適用于需要大量小數(shù)組供短暫使用的場景介褥。不能把它用于大數(shù)組或者深度遞歸函數(shù),因為那可能會超出可用的椀萃铮空間柔滔。
棧分配Span
棧分配數(shù)組的一個安全替代方案是棧分配Span。消除指針萍虽,也就消除了緩沖區(qū)溢出的可能性睛廊。反過來,這意味著你可以使用它而不必把方法標(biāo)記為不安全的杉编。
Span<int> block = stackalloc int[3] { 1, 2, 3 };
注意超全,Span依賴于NuGet包System.Memory。
可重新賦值的Ref局部變量
Ref局部變量現(xiàn)在可以和普通局部變量一樣重新賦值了邓馒。
小結(jié)
本文講解了C#7.3的新特性中對Unity編程有影響的新特性嘶朱,不過這些特性得等到Unity2018.3才可以用哦。
洪流學(xué)堂公眾號回復(fù)runtime
光酣,獲取本系列所有文章疏遏。
把今天的內(nèi)容分享給其他Unity開發(fā)者朋友,或許你能幫到他救军。