由于尽管在CLR中有一些支持,但不变性并没有完全融入C#到F#的程度,或完全进入框架(BCL),对于C#的(im)可变性有什么相当完整的解决方案?
我的偏好顺序是一个由兼容的一般模式/原则组成的解决方案
那
我还希望包含您作为社区可能提出的模式,这些模式不完全适合框架,例如通过接口表达可变性意图(其中两个客户端不应该更改某些内容并且可能只想更改某些内容通过接口这样做,而不是支持类(是的,我知道这不是真正的不变性,但足够):
public interface IX
{
int Y{ get; }
ReadOnlyCollection<string> Z { get; }
IMutableX Clone();
}
public interface IMutableX: IX
{
new int Y{ get; set; }
new ICollection<string> Z{ get; } // or IList<string>
}
// generally no one should get ahold of an X directly
internal class X: IMutableX
{
public int Y{ get; set; }
ICollection<string> IMutableX.Z …Run Code Online (Sandbox Code Playgroud) 我在我的应用程序中创建了大多数基本类型,不可变.但收藏品是否也应该是不可变的?对我来说,这似乎是一个巨大的开销,除非我错过了什么.
我在谈论集合以保存Point3值等,可以在不同时间添加它们.因此,如果集合中有1M值,并且您需要删除其中的1个,则必须重新创建相同的集合,对吧?
我最近开始使用F#进行"实际工作",并重新发现了不可变数据结构的美妙之处,例如F#中的歧视联盟和记录.我还发现它们很容易从C#中使用,特别是因为它们不需要对F#运行时有任何直接依赖.但是,在表示这些结构中的列表时,我还没有找到理想的解决方案.
我的第一次尝试是将列表键入为seq <'a>(在C#世界中为IEnumerable),它提供了一个很好的通用集合接口,而不像ICollection <>及其朋友那样导出任何改变集合的方法.但是,由于我无法控制受歧视的联合或记录的构造函数,因此这些类型的实例的创建者可以提供可能在使用时更改或抛出的IEnumerable <>实现(例如LINQ表达式) .IEnumerable <>因此不会给编译器提供任何帮助,证明该值是不可变的,因此线程安全.
我目前的策略是使用F#list类型,它确保了一个不可变的集合,但是在F#运行时添加了一个依赖项,当从非F#项目中使用它时看起来有些偏差.但它确实允许IEnumerable <>没有的F#模式匹配.它也没有在列表的实际表示中给出任何选择,并且在某些情况下(例如原始值的大列表),F#列表表示并不真正适合.
我真正希望看到的是.NET中的不可变数组类型,表示与普通数组一样紧凑,但编译器保证不会发生变异.我会像C++一样欢迎const,尽管它可能不太可能发生.与此同时,我还有其他选择吗?
更具体地说,我真的想要一个不可变/共享的链表,我认为拥有不可变的地图和集合也会很好.只要我不必担心核心实现,我就可以轻松添加扩展方法/子类/包装它,为我自己提供一个合理的外部接口.
我有什么理由不这样做吗?性能,不兼容性等?