[英]Can I call this C# class “immutable”?
我需要使我的可變類不可變 ,現在它看起來如下。 但是,我仍然不確定我是否有一個完全“不可變的*類,如果是這樣,那么這個叫做什么樣的不變性 ?
public class B<C, M>
where C : IComparable<C>
where M : IMetaData
{
internal B(char tau, M metadata, B<C, M> nextBlock)
{
if (tau == 'R') omega = 1;
_lambda = new List<Lambda<C, M>>();
_lambda.Add(new Lambda<C, M>(tau: tau, atI: metadata));
foreach (var item in nextBlock.lambda)
if (item.tau != 'L')
_lambda.Add(new Lambda<C, M>(tau: 'M', atI: item.atI));
}
internal int omega { private set; get; }
private List<Lambda<C, M>> _lambda { set; get; }
internal ReadOnlyCollection<Lambda<C, M>> lambda { get { return _lambda.AsReadOnly(); } }
internal B<C, M> Update(int Omega, char tau, M metadata)
{
B<C, M> newBlock = new B<C, M>();
newBlock.omega = Omega;
newBlock._lambda = new List<Lambda<C, M>>(this._lambda);
newBlock._lambda.Add(new Lambda<C, M>(tau: tau, atI: metadata));
return newBlock;
}
internal B<C, M> Update(Dictionary<uint, Lambda<C, M>> lambdas)
{
B<C, M> newBlock = new B<C, M>();
newBlock.omega = this.omega;
newBlock._lambda = new List<Lambda<C, M>>();
foreach (var l in lambdas)
newBlock._lambda.Add(new Lambda<C, M>(tau: l.Value.tau, atI: l.Value.atI));
return newBlock;
}
}
public class Lambda<C, M>
where C : IComparable<C>
where M : IMetaData
{
internal Lambda(char tau, M atI)
{
this.tau = tau;
this.atI = atI;
}
internal char tau { private set; get; }
internal M atI { private set; get; }
}
根據我的申請B
需要不時更改; 因此,為了保持不變性的屬性,每次更新都需要通過Update
函數來完成,該函數返回一個全新的B
要了解Jon Skeet巧妙發現的IMetaData
,請考慮以下定義:
public interface IMetaData
{
UInt32 hashKey { set; get; }
}
以下類作為M
傳遞給B<C, M>
public class MetaData : IMetaData
{
public UInt32 hashKey { set; get; }
}
沒有任何外部代碼可以觀察到這種類型的任何突變,這足以使它在常見的語言中被認為是“不可變的”。 它曾經變異的唯一時間是它自己的構造函數; 它一旦創建就永遠不會變異,所以沒有任何外部實體能夠真正觀察到類型的變異。 幾乎所有被認為是“不可變的”類型都會出現這種情況。
雖然該類型確實具有在其構造函數之外變異的技術能力,因為它具有不是readonly
字段以及可變List
,但它實際上從不執行任何此類突變或暴露任何變異數據的方法。
絕大多數不可變類類型通過將數據封裝在可變類類型的對象中來實現其不變性,但確保不會將對該對象的引用暴露給可能使其變異的代碼。 鑒於.NET沒有除String
之外的任何不可變數組類型,這種方法通常是可變大小集合提供有效隨機訪問的唯一實用方法。 不需要提供有效隨機訪問的類型可以使用更多“深度不可變”的方式來存儲數據,例如鏈接列表或樹,它們將所有內容存儲在readonly
字段中,但實際上,如果沒有可能的執行順序,通過它可以通過特定對象實例可以進行變異,然后該特定實例可以被合法地描述為“不可變”,即使它的類允許實例被引用它的任何人變異。
關於接口類型引用是否可以被視為標識不可變對象,這將取決於接口本身或提供引用的方式中是否存在合同,這將指定所有該接口的合法實現將是不可變的,由引用標識的特定實例將是不可變的,或者(如果持有引用的代碼永遠不會將其公開給外部代碼)該實例將永遠不會暴露給可能使其變異的代碼。 如果接口承諾不變,那么從外部代碼接收引用的代碼可以直接使用它; 否則,它必須從代碼中接收引用,該代碼承諾不會對其進行任何“未經過保護的”引用。 一種可能的模式是讓接口提供一個AsReadableSnaphot
方法,該方法可以保證在調用它時返回一個封裝對象狀態的對象,並保證不存在會改變所討論對象的外部引用; 一個不可變的類可能會實現這樣一個方法來簡單地返回自己,而一個可變的類可能實現它來返回它自己的克隆)。 如果類的實例可能很大,那么可能需要讓AsReadableSnapshot
創建一個不可變的類實例(這樣調用AsReadableSnapshot
就不必在其中創建另一個數據副本)但如果它們總是很小,那么返回的對象是一個可變類型應該不是問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.