未来的C#之只读引用与结构体
C++中提供了const特性,使用該特性定義的參數(shù),其所引用的參數(shù)或?qū)ο髮⒉粫徽{(diào)用函數(shù)修改(當然const還提供了更多的特性,參見“Const正確性”)。在新的建議中,C#也將提供類似的特性。
只讀ref參數(shù)
在C#中,“只讀引用”也可稱為“in參數(shù)”,兩者提供了類似的限制。只讀引用的基本思想是,如果用“readonly ref”或僅是“in”標注一個參數(shù),那么編譯器會解釋為“將該參數(shù)按引用傳遞以改進性能,但不允許實際更改該參數(shù)”。該特性對于在高性能場景下的大型結(jié)構(gòu)體尤為有用。在建議中引用了如下的例子:
我們知道,在XNA等圖形庫中的向量/矩陣數(shù)學運算符是具有ref操作符的,這純粹是出于性能上的考慮。Roslyn編譯器本身就有代碼使用了結(jié)構(gòu)體,以避免內(nèi)存分配,并可通過引用的方式傳遞結(jié)構(gòu)體,免除復制的繁瑣。
該語法還結(jié)合了C++版本的const。即參數(shù)本身是不可更改的,參數(shù)所引用的對象或結(jié)構(gòu)體中的所有數(shù)據(jù)也是不可更改的。
當前在通過引用傳遞一個參數(shù)時,必須使用“ref”或“out”關(guān)鍵字。在這個建議實現(xiàn)后,使用“in”參數(shù)無需受此限制。進而表達式的結(jié)果也可以傳遞進來(當前這在VB中是允許的,但是在C#中尚不允許)。
實現(xiàn)細節(jié)
對比“ref”和“out”參數(shù),它們的重載規(guī)則具有相同的工作機制。
這依然有待議定,但是當前的計劃是不允許“in”參數(shù)被匿名函數(shù)或async函數(shù)捕獲(即生成一個閉包對象)。捕獲“in”參數(shù)的問題在于會導致一次拷貝,這破壞了使用“in”參數(shù)的初衷,即避免拷貝所導致的性能損耗。
將參數(shù)標為“readonly ref”或“in”,并不會令引用值成為不可變值。雖然參數(shù)值無法被聲明函數(shù)更改,但可以在其它地方修改。無需使用多線程,只需能訪問參數(shù)所引用原始變量的方法即可。
在結(jié)構(gòu)體上調(diào)用方法可能會導致問題。在建議中是這樣說的:
結(jié)構(gòu)體的所有常規(guī)實例方法可轉(zhuǎn)變(mutate)實例,或是對實例暴露引用(ref-expose),因此必須要創(chuàng)建一個臨時拷貝,正如當前對接收者是只讀域時的做法。
但是,由于沒有考慮向后兼容,也不存在變通方案,所以編譯器只是給出一個警告,以確保用戶留意到這一隱式拷貝。
使用“out”參數(shù)時,一個特殊的參數(shù)標識了是否需要“in”參數(shù)。該參數(shù)將被舊的編譯器忽略,因此沒有向后兼容的問題。
只讀ref返回
與該特性密切相關(guān)的是將ref returns標為只讀的功能。開發(fā)人員使用“in”參數(shù),主要因為它能提供良好的性能,但是“in”參數(shù)不允許返回表達式的結(jié)果。返回值必須是正常ref返回的一個合法變量,其中可以包含數(shù)組元素、ref參數(shù)和對象中的域。
ref/in的擴展方法
“ref”擴展方法將允許擴展方法修改傳遞進來的結(jié)構(gòu)體。需要編譯器能驗證傳遞給ref擴展方法的參數(shù)是可變的。
雖然“in”擴展方法不允許修改參數(shù),但對于性能敏感的代碼依然十分有用,尤其是結(jié)構(gòu)體非常大的時候。這時當然不需要一個可變參數(shù)。
在上面兩種情況下,該特性只能用于結(jié)構(gòu)體。
編輯按:假定廣泛使用了PureAttribute,編譯器將不允許對“in”擴展方法調(diào)用非PureAttribute的方法。但由于對性能并無太大改善,因此不大可能廣泛應用。
只讀結(jié)構(gòu)體
將結(jié)構(gòu)體變量標為readonly可能會對性能產(chǎn)生影響。編譯器無法確定某個調(diào)用是否會對結(jié)構(gòu)體產(chǎn)生改動,因此會默認能夠修改,并始終復制只讀結(jié)構(gòu)體變量的副本。
使用該特性,開發(fā)人員可以在類型層面上將整個結(jié)構(gòu)體標為只讀。這樣一來,編譯器就知道:在通過只讀結(jié)構(gòu)體的變量暴露該只讀結(jié)構(gòu)體時,不需要進行拷貝。
在建議中指出:
唯一一個顯而易見的問題在于:是否需要將其中一些方法改為賦值(mutator)方法。
目前,對只讀結(jié)構(gòu)體進行逐個控制只會增加不必要的復雜性,我們可以后期需要時再行添加。
當前,我們假定可變和不可變成員“混合”的結(jié)構(gòu)體并不常見。此外,可變結(jié)構(gòu)體的部分變量通常需要是LValues,從而避免隱式拷貝的影響。
缺點
建議還指出,這些功能對已有代碼不大可能有幫助,但在如下新場景中會很有用,例如:
在計算能力關(guān)乎費用,響應能力關(guān)乎競爭優(yōu)勢的云場景或數(shù)據(jù)中心場景下。
對延遲有軟性實時需求的游戲/VR/AR場景。
在建議中也提出了警告,在“in”參數(shù)上的限制可循環(huán)作用于被調(diào)用函數(shù)。但這一問題并不嚴重,因為已經(jīng)可以使用“out”參數(shù)執(zhí)行同一操作了。
原文地址:http://www.infoq.com/cn/news/2017/04/Readonly-References
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的未来的C#之只读引用与结构体的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET跨平台实践:再谈用C#开发Lin
- 下一篇: 了解 C# foreach 内部语句和使