OK, so C# doesn’t share the Rust concept of “borrowing,” so it wouldn’t technically be correct to call this “borrow checking,” but in practice when people talk about “Rust’s borrow checker” they’re talking about all of the static analysis Rust does to ensure memory safety, for which I think this qualifies.
When I first saw this feature in C# (and also Spans, ref structs, and stackalloc), I was blown away: where are all the angle brackets and apostrophes? How is it possible that I can write efficient and provably-safe code in C# without a degree in type theory? In this document I hope to briefly summarize my understanding of memory safety in C#, make direct comparisons between C# constructs and the corresponding Rust ones, and maybe shed some light on what trade-offs C# made exactly to get this so user-friendly.
Since the beginning (2000-ish), C# has had the ref keyword for parameters passed into a function by reference, but that was about all you could do with it. If you wanted to do efficient things with stack-allocated memory and indirection, you would generally use the “unsafe” portions of the language, or call out to C++. It wasn’t until 2017 with the release of C# version 7 that we started to see this feature generalized into something more useful. From there, C# added: