C# 中什么是突变?

Cen*_*nko 6 .net c# mutation

我正在阅读 Joseph Albahari 的书“C# 10 in a Nutshell”,它谈到“匿名类型的非描述性突变”,但我什至不知道突变是什么,在谷歌上我能找到的只是“突变测试”或“什么是突变”非破坏性突变?” 它们总是作为记录类型的附带功能而结束。有人可以帮我分解一下吗?一些例子将不胜感激!

Hei*_*nzi 10

To mutate (in the sense used in "nondesctructive mutation for anonymous types") just means to change the state of an object. Here is a simple example:

var sb = new StringBuilder("Hello");

// We mutate the object referenced by sb, so that it contains
// "Hello!" rather than "Hello".
sb.Append("!")

Console.WriteLine(sb.ToString());   // prints Hello!
Run Code Online (Sandbox Code Playgroud)

StringBuilder is a mutable class. Other classes, such as String, are immutable:

var s = "Hello";

// The following expression returns a *new* string "hello",
// but does not mutate the original string itself.
s.ToLower();

Console.WriteLine(s);   // still prints Hello
Run Code Online (Sandbox Code Playgroud)

So, what do we do if we want to mutate the contents of an immutable class, for example, to lowercase the contents of a string? We create a new object that contains the modified version. This is what string.ToLower does:

var s1 = "Hello";
var s2 = s1.ToLower();

Console.WriteLine(s1);   // prints Hello
Console.WriteLine(s2);   // prints hello
Run Code Online (Sandbox Code Playgroud)

This is called non-destructive mutation: The original string s1 still exists, it has not been destroyed. On the other hand, sb.Append("!") in the very first example was destructive: The version of sb containing Hello (without exclamation mark) is no longer accessible.

(Obviously, you can re-use the same variable name when lowercasing a string, e.g. s = s.ToLower(). But that does not change the fact that ToLower creates a new object rather than modifying the old one in-place. s = ... ensures that the variable s points to the new object afterwards.)


So, what does this have to do with anonymous types? Anonymous types in C# are immutable:

var myObject = new { A = 1, B = 2 };

myObject.B = 3;   // <- yields a compile-time error
Run Code Online (Sandbox Code Playgroud)

C#9 introduced the with keyword, which allows you to create a new object which is an exact copy of the original object, except for the values you want to change:

var o1 = new { A = 1, B = 2 };
var o2 = o1 with { B = 3 };
    
// o1: A = 1, B = 2
// o2: A = 1, B = 3
Run Code Online (Sandbox Code Playgroud)