我可以称之为“C类”吗;不可变”;

本文关键字:不可变 称之为 我可以 | 更新日期: 2023-09-27 18:28:41

我需要使我的类是可变的类不可变,现在看起来如下。然而,我仍然不确定我是否有一个完全"不可变"的类,如果是,这被称为什么样的不变性

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需要不时更改;因此,为了保持不变性的特性,每次更新都需要通过返回全新BUpdate函数来完成。

更新

要了解Jon Skeet巧妙发现的IMetaData,请考虑以下定义:

public interface IMetaData
    {
        UInt32 hashKey { set; get; }
    }

并且下面的类作为M传递到B<C, M>

public class MetaData : IMetaData
    {
        public UInt32 hashKey { set; get; }
    }

我可以称之为“C类”吗;不可变”;

没有任何外部代码可以观察到这种类型的任何突变,这足以使它在公共语言中被认为是"不可变的"。它唯一发生变异的时候是在它自己的构造函数期间;它一旦产生就不会发生突变,因此没有任何外部实体能够真正观察到这种类型的突变。几乎所有被认为"不可变"的类型都是如此。

虽然该类型确实具有在构造函数之外进行自身变异的技术能力,因为它既有非readonly的字段,也有可变的List,但它从未实际执行过任何此类变异,也从未公开过任何变异数据的方法。

绝大多数不可变类类型通过将数据封装在可变类类型的对象中,但确保对该对象的引用永远不会暴露给可能使其发生变异的代码来实现其不变性。考虑到.NET除了String之外没有任何不可变数组类型,这种方法通常是可变大小集合提供有效随机访问的唯一实用方法。不需要提供有效随机访问的类型可以使用更"深度不可变"的方式来存储数据,如链表或树,这些数据将所有内容存储在readonly字段中,但在实践中,如果没有可能的执行序列来突变特定的对象实例,则该特定实例可以被合法地描述为"不可变的",即使它的类允许引用它的任何人对该实例进行变异

关于接口类型引用是否可以被视为标识不可变对象,这将取决于接口本身或提供引用的方式中是否存在契约,该契约将指定该接口的所有合法实现都是不可变的,引用所标识的特定实例将是不可变的,或者(如果持有引用的代码从未将其暴露给外部代码)该实例永远不会暴露给可能使其发生变异的代码。如果接口承诺具有不变性,那么从外部代码接收引用的代码可以直接使用它;否则,它将不得不从代码中接收引用,该代码承诺不会有任何"未屏蔽"的引用。一种可能的模式是让接口提供AsReadableSnaphot方法,该方法将保证在调用对象时返回一个封装对象状态的对象,并承诺不存在会使所涉对象发生变异的外部参照;一个不可变的类可能实现这样一个方法来简单地返回它自己,而一个可变的类则可能实现它来返回它自己的克隆)。如果类的实例可能很大,那么最好让AsReadableSnapshot创建一个不可变的类实例(这样调用AsReadableSnapshot就不必再复制其中的数据),但如果它们总是很小,那么让返回的对象是可变类型应该不会有问题。