[英]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.