如何确定一个类在C#中是不可变的?

如何确定一个类在C#中是不可变的?

ImmutableObjectAttribute ,但这很少使用且支持不足 – 当然也没有强制执行(你可以用[ImmutableObject(true)]标记一个可变对象.AFAIK,这唯一影响的是IDE处理属性的方式(即显示/不显示命名属性选项)。

实际上,您必须检查FieldInfo.IsInitOnly ,但这仅适用于真正的100%不可变类型(假设没有reflection滥用等); 它对冰棒不变性没有帮助,也没有在实践中不变的东西,但在实施中却没有; 即它们不能被公开变为可变,但理论上该对象支持它。

这里的一个典型例子是字符串…每个人都“知道” string是不可变的…当然, StringBuilder 确实会改变引擎盖下的字符串。 不,认真……

鉴于此,很难定义不变性,更不用说强有力地检测它了……

你不能,你只能猜。 如果所有字段都是只读的,那么一旦构造函数完成,实例将是不可变的。 这很重要,如果您有以下内容,它将显示为实例栏可变。

 class Foo { public readonly int X public readonly int Y public Foo(int x, int y, Bar bar) { this.X = x; bar.ShowYourself(this); this.Y = y; bar.ShowYourself(this); } } 

但是,如果所谓的不可变类上的字段是一个集合(并且不是只读的)那么调用该类不可变可能是不正确的(因为它的状态可以改变)

请注意,即使所有字段都是只读,也允许reflection修改字段。

检查属性上没有setter确实是一个非常差的启发式。

部分问题是“不可变”可能有多重含义。 举例来说,ReadOnlyCollection

我们倾向于认为它是不可改变的。 但是,如果它是一个ReadOnlyCollection 呢? 另外,因为它实际上只是IList的一个包装器,所以我会传递给构造函数,如果我改变原来的IList怎么办?

一个好的方法可能是创建一个名为ReadOnlyAttribute的属性,并将您认为只读的类标记为它。 对于您无法控制的类,您还可以维护一组您认为不可变的已知类型。

编辑:有关不同类型的不变性的一些很好的例子,请阅读Eric Lippert的这一系列post: http : //blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one -kinds-的-immutability.aspx

据我所知,除非明确记录,否则无法确定C#中的类是否是不可变的。

但是,您可以使用Reflection来检查属性上是否存在Setter; 但是,缺少setter并不能保证不变性,因为内部状态可能会改变这些属性的值,无论您是否可以明确设置它们。

此外,再次使用Reflection检查所有类的字段的’IsInitOnly’标志可能表示不变性,但它不保证它。

编辑: 这是一个类似的问题 ,询问Java语言,其答案也适用于此。

通过代码,我不确定,但是afaik如果你看另一个不可变类型的IL,比如一个字符串,你将看不到newobj IL指令(你会看到字符串的ldstr),也许是检查IL的创作可能是一种说法,只是猜测……

从运行时获得的唯一帮助是,如果类中的所有字段都使用“readonly”进行注释。 [编辑,参见@ShuggyCoUk]即便如此,CLR也会让你写下来。 我刚刚validation了它。 啊。

您可以通过reflection从类中获取FieldInfo对象并检查IsInitOnly。