.Net 中不可变类型的示例

Examples of Immutable Types in .Net

我们知道不变性的概念,但除了

之外还需要了解一些不可变类型

还有吗?

TimeSpan,或现代型家庭TupleTuple 是不可变的,因为它实现为支持 .NET 中的函数式语言 (F# f.e。)。

当然,您可以根据需要使自己的 classes 和结构可变或不可变。不可变类型(又名值对象)在多线程编程、函数式编程中很有用,可以清除代码。

要使 class 或结构不可变,只需删除所有 public/protected/internal setter;最好用 readonly 关键字声明所有字段。

框架 class 库中的不可变类型列表如下。 (随意扩展它!)

System.…

  • 所有原始值类型:(注意:!)
    • ByteSByte
    • Int16UInt16
    • Int32UInt32
    • Int64UInt64
    • IntPtr
    • Single
    • Double
  • Decimal
  • 编译器创建的所有匿名类型(C#中的new { ... },VB.NET中的New With { ... } (错误有两个原因:这些类型不在 FCL 中,显然 VB.NET 类型是可变的。)
  • 所有枚举类型(enumEnum
  • 所有代表类型。 (请参阅 。虽然委托似乎是可变的(因为您可以执行 obj.PropertyChanged += callback 之类的操作,但实际上 obj.PropertyChanged 引用已变异为指向新建委托实例,原委托实例保持不变。)
  • DateTimeTimeSpan (在 中提到)DateTimeOffset
  • DBNull
  • Guid
  • Nullable<T>
  • String
  • .NET 4 引入的 Tuple<…> 类型 (在 中提到)
  • Uri
  • Version
  • Void

System.Linq.…

  • Lookup<TKey, TElement>

我不确定您是在寻找 public.NET 中的不可变类型还是完全不可变的类型。此外,您只想处理 .NET 中的 public 类型?更深层次的问题是定义什么构成不变性。做一个只有

的 class
public readonly int[] Numbers;

让它不可变?数字本身不能更改,但其内容可以。你明白了。

无论如何,您可以以编程方式检查自己。对于更深层次的嵌套检查,你将需要递归(我不会在这里做)

加载您要检查的所有程序集,并执行类似(未测试)

var immutables = AppDomain.CurrentDomain
                .GetAssemblies()
                .SelectMany(t => t.GetTypes())
                .Where(t => t
                           .GetProperties(your binding flags depending on your definition)
                           .All(p => !p.CanWrite) 
                         && t
                           .GetFields(your binding flags depending on your definition)
                           .All(f => f.IsInitOnly)
                .ToList();

即使这样也不足以找到集合类型的不变性。一些不可变的集合类型(虽然不是默认 .NET 核心的一部分)可以在这里找到:Immutable Collections


一些值得注意的不可变对象:

  • 一些 class 类型,例如 StringTuple、匿名类型
  • 大多数结构(值得注意的例外包括大多数枚举数)
  • 枚举
  • 代表
  • 不可变集合类型,如

    ImmutableArray(预发行版)

    不可变字典

    ImmutableSortedDictionary

    ImmutableHashSet

    不可变列表

    不可变队列

    不可变排序集

    不可变堆栈

一些示例来自 mscorlib:

  • 所有原始类型
  • 枚举
  • decimal
  • (U)IntPtr
  • DateTimeDateTimeOffsetTimeSpan
  • KeyValuePair<,> - 相反,DictionaryEntry 不是不可变的
  • Tuple<...>
  • (Multicast)Delegate - 与字符串类似,更改时总是返回一个新实例。
  • Guid
  • Version

有趣的是,string 实际上并不是一成不变的;但是,我们可以将其视为 "practically immutable" 类型,这意味着字符串实例的内容不能通过 public 方式更改(至少在安全上下文中)。但是它有一个 wstrcpy 内部方法,StringBuilder class 使用它来操作字符串实例。

有了 .NET 5 和新的 C# 9.0 版本,几乎每个对象现在都可以是不可变的(或在属性中包含不可变状态)

更多信息请点击此处:https://martinstanik.com/2020/10/09/immutable-data-types-after-net-5-release/