Many of these features exist since .NET 1.0, given its scope of languages to support, including C++.
So even those that weren't initially exposed in unsafe mode, were available at the MSIL level and could be generated via helper methods making use of "System.Reflection.Emit".
Naturally having them as C# language features is more ergonomic and safer than a misuse of MSIL opcodes.
There is a runtime (not C#) feature that has been added that is relevant to the article: ref fields in structs. Before these, only certain runtime-blessed types like Span<T> could contain refs directly.
In case anyone is interested, here is the spec about refs in structs and other lifetime features mentioned in the article:
I believe you can avoid most of not all of the P/invoke overhead these days by using unmanaged function pointers and not using the automatic marshalling.
Whenever you use [DllImport], the analyzer will nudge you to auto-fix it to [LibraryImport] which source-generates a marshalling stub (if any is needed) that then calls an inner [DllImport] that does not require runtime marshalling. This is very cheap since function address gets cached into a readonly static which then gets baked into the machine code once the JIT produces Tier-1 compilation for your method.
On NativeAOT, you can instead use "DirectPInvoke" which links against specified binary and relies on system loader just like C/C++ code would. Then, you can also statically link and embed the dependency into your binary (if .lib/.a is available) instead which will turn pinvokes into direct calls (marshalling if applicable and GC frame transition remain, on that read below).
Lastly, it is beneficial to annotate short-lived PInvoke calls with [SuppressGCTransition] which avoids some deoptimizations and GC frame transition calls around interop and makes the calls as cheap as direct calls in C + GC poll (a single usually not-taken branch). With this the cost of interop effectively evaporates which is one of the features that makes .NET as a relatively high-level runtime so good at systems programming.
Unmanaged function pointers have similar overhead, and identical if you apply [SuppressGCTransition] to them in the same way.
* LibraryImport is not needed if pinvoke signature only has primitives, structs that satisfy 'unmanaged' constraint or raw pointers since no marshalling is required for these.
I'm not sure I follow. Where are GUI workloads being discussed in the article?
If anything, article doesn't talk about MSIL or CLR, but C# language features. CLR is not the only target C# supports.
NativeAOT is supported in Avalonia (cross-platform UI framework), Razor Slices (dynamically render HTML from Minimal APIs) and I think there is also some support for AOT in MonoGame & FNA (game dev frameworks).
However, it's still early and a lot of the ecosystem doesn't support NativeAOT.
So even those that weren't initially exposed in unsafe mode, were available at the MSIL level and could be generated via helper methods making use of "System.Reflection.Emit".
Naturally having them as C# language features is more ergonomic and safer than a misuse of MSIL opcodes.