简体   繁体   中英

How to determine if .NET (BCL) type is immutable

From this Answer , I came to know that KeyValuePair are immutables.

I browsed through the docs , but could not find any information regarding immutable behavior.

I was wondering how to determine if a type is immutable or not?

I don't think there's a standard way to do this, since there is no official concept of immutability in C#. The only way I can think of is looking at certain things, indicating a higher probability:

1) All properties of the type have a private set

2) All fields are const / readonly or private

3) There are no methods with obvious/known side effects

4) Also, being a struct generally is a good indication (if it is BCL type or by someone with guidelines for this)

Something like an ImmutabeAttribute would be nice. There are some thoughts here (somewhere down in the comments), but I haven't seen one in "real life" yet.

The first indication would be that the documentation for the property in the overview says "Gets the key in the key/value pair." The second more definite indication would be in the description of the property itself:

"This property is read/only."

I don't think you can find "proof" of immutability by just looking at the docs, but there are several strong indicators:

  • It's a struct ( why does this matter? )
  • It has no settable public properties (both are read-only)
  • It has no obvious mutator methods

For definitive proof I recommend downloading the BCL's reference source from Microsoft or using an IL decompiler to show you how a type would look like in code.

A KeyValuePair<T1,T2> is a struct which, absent Reflection, can only be mutated outside its constructor by copying the contents of another KeyValuePair<T1,T2> which holds the desired values. Note that the statement:

MyKeyValuePair = new KeyValuePair(1,2);

like all similar constructor invocations on structures, actually works by creating a new temporary instance of KeyValuePair<int,int> (happens before the constructor itself executes), setting the field values of that instance (done by the constructor), copying all public and private fields of that new temporary instance to MyKeyValuePair , and then discarding the temporary instance.

Consider the following code:

static KeyValuePair MyKeyValuePair;  // Field in some class

// Thread1
  MyKeyValuePair = new KeyValuePair(1,1);
  // ***
  MyKeyValuePair = new KeyValuePair(2,2);

// Thread2
  st = MyKeyValuePair.ToString();

Because MyKeyValuePair is precisely four bytes in length, the second statement in Thread1 will update both fields simultaneously. Despite that, if the second statement in Thread1 executes between Thread2's evaluation of MyKeyValuePair.Key.ToString() and MyKeyValuePair.Value.ToString() , the second ToString() will act upon the new mutated value of the structure, even though the first already-completed ToString() operated upon the value before the mutation.

All non-trivial structs, regardless of how they are declared, have the same immutability rules for their fields: code which can change a struct can change its fields; code which cannot change a struct cannot change its fields. Some structs may force one to go through hoops to change one of their fields, but designing struct types to be "immutable" is neither necessary nor sufficient to ensure the immutability of instances. There are a few reasonable uses of "immutable" struct types, but such use cases if anything require more care than is necessary for structs with exposed public fields.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM