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

时间:2022-05-24 08:50:52

How do I find out if a class is immutable in C#?

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

6 个解决方案

#1


There is ImmutableObjectAttribute, but this is rarely used and poorly supported - and of course not enforced (you could mark a mutable object with [ImmutableObject(true)]. AFAIK, the only thing this this affects is the way the IDE handles attributes (i.e. to show / not-show the named properties options).

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

In reality, you would have to check the FieldInfo.IsInitOnly, but this only applies to truly 100% immutable types (assuming no reflection abuse, etc); it doesn't help with popsicle immutability, nor things that are immutable in practice, but not in their implementation; i.e. they can't be made to be publicly mutable, but in theory the object supports it.

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

A classic example here would be string... everyone "knows" that string is immutable... of course, StringBuilder does mutate a string under the bonnet. No, seriously...

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

It is so hard to define immutability given this, let alone robustly detect it...

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

#2


You cannot, you can only guess. If all fields are readonly the the instances will be immutable once the constructor finishes. This is important, if you had the following it would appear mutable to the instance bar.

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

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);
    }
}

However if a field on the supposedly immutable class was a collection (and was not read only) then calling the class immutable would likely be incorrect (since it's state can change)

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

Note that even if all fields are readonly reflection is allowed to modify the fields.

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

Checking for no setters on properties will be a very poor heuristic indeed.

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

#3


Part of the problem is that "immutable" can have multiple meanings. Take, for example, ReadOnlyCollection<T>.

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

We tend to consider it to be immutable. But what if it's a ReadOnlyCollection<SomethingChangeable>? Also, since it's really just a wrapper around an IList I pass in to the constructor, what if I change the original IList?

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

A good approach might be to create an attribute with a name like ReadOnlyAttribute and mark classes you consider to be read-only with it. For classes you don't control, you can also maintain a list of known types that you consider to be immutable.

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

EDIT: For some good examples of different types of immutability, read this series of postings by Eric Lippert: http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx

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

#4


To my knowledge, unless it's explicitly documented, there is no way to determine whether a class is immutable or not in C#.

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

You can, however, use Reflection to check for the existence of Setters on properties; however, lack of setters does not guarantee immutability as internal state may change the values of these properties whether you can explicitly set them or not.

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

Additionally, checking for the 'IsInitOnly' flag for all the class's fields, again using Reflection, might indicate immutability, but it doesn't guarantee it.

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

Edit: Here's a similar question, asked regarding the Java language, whose answer also applies here.

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

#5


Via code, I'm not sure, but afaik if you look at the IL of another immutable type, such as a string you will not see a newobj IL instruction (you'll see ldstr for strings), perhaps inspecting the IL of the creation may be one way to tell, just a guess...

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

#6


The only help you get from the runtime is if all the fields in the class are annotated with "readonly". [Edit, see @ShuggyCoUk] And even then the CLR will let you write over it. I just verified it. Ugh.

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

You can get the FieldInfo objects from the class via reflection and check IsInitOnly.

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

#1


There is ImmutableObjectAttribute, but this is rarely used and poorly supported - and of course not enforced (you could mark a mutable object with [ImmutableObject(true)]. AFAIK, the only thing this this affects is the way the IDE handles attributes (i.e. to show / not-show the named properties options).

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

In reality, you would have to check the FieldInfo.IsInitOnly, but this only applies to truly 100% immutable types (assuming no reflection abuse, etc); it doesn't help with popsicle immutability, nor things that are immutable in practice, but not in their implementation; i.e. they can't be made to be publicly mutable, but in theory the object supports it.

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

A classic example here would be string... everyone "knows" that string is immutable... of course, StringBuilder does mutate a string under the bonnet. No, seriously...

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

It is so hard to define immutability given this, let alone robustly detect it...

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

#2


You cannot, you can only guess. If all fields are readonly the the instances will be immutable once the constructor finishes. This is important, if you had the following it would appear mutable to the instance bar.

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

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);
    }
}

However if a field on the supposedly immutable class was a collection (and was not read only) then calling the class immutable would likely be incorrect (since it's state can change)

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

Note that even if all fields are readonly reflection is allowed to modify the fields.

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

Checking for no setters on properties will be a very poor heuristic indeed.

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

#3


Part of the problem is that "immutable" can have multiple meanings. Take, for example, ReadOnlyCollection<T>.

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

We tend to consider it to be immutable. But what if it's a ReadOnlyCollection<SomethingChangeable>? Also, since it's really just a wrapper around an IList I pass in to the constructor, what if I change the original IList?

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

A good approach might be to create an attribute with a name like ReadOnlyAttribute and mark classes you consider to be read-only with it. For classes you don't control, you can also maintain a list of known types that you consider to be immutable.

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

EDIT: For some good examples of different types of immutability, read this series of postings by Eric Lippert: http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx

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

#4


To my knowledge, unless it's explicitly documented, there is no way to determine whether a class is immutable or not in C#.

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

You can, however, use Reflection to check for the existence of Setters on properties; however, lack of setters does not guarantee immutability as internal state may change the values of these properties whether you can explicitly set them or not.

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

Additionally, checking for the 'IsInitOnly' flag for all the class's fields, again using Reflection, might indicate immutability, but it doesn't guarantee it.

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

Edit: Here's a similar question, asked regarding the Java language, whose answer also applies here.

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

#5


Via code, I'm not sure, but afaik if you look at the IL of another immutable type, such as a string you will not see a newobj IL instruction (you'll see ldstr for strings), perhaps inspecting the IL of the creation may be one way to tell, just a guess...

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

#6


The only help you get from the runtime is if all the fields in the class are annotated with "readonly". [Edit, see @ShuggyCoUk] And even then the CLR will let you write over it. I just verified it. Ugh.

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

You can get the FieldInfo objects from the class via reflection and check IsInitOnly.

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

相关文章