Skip to content

C# and .NET docs supplement

James Groom edited this page Mar 16, 2023 · 45 revisions

To save us repeating our complaints about the lack of proper documentation under each section, let's agree to gather all the frustration here:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Contribute to the official docs if possible.

Deceptive collection type names

IReadOnly{Collection,Dictionary,List,Set} are for getting read-only views of the collections that implement them. They do not mean the collection is immutable (there are separate classes for that). The same goes for ReadOnlySpan.

Kotlin got this right by calling its interfaces e.g. List/MutableList instead of IReadOnlyList/IList. (And it also fixed the inheritance hierarchy.)

Featureset is determined by language level AND target

see feature matrix page

Guarded default in switch statements

You can only have 1 default branch, but case _ when ...: doesn't work. However, case var _ when ...: does.

MSBuild Condition placement

On (older versions of?) VS, Condition is ignored if placed on a property. Create a new <PropertyGroup/>.

MSBuild property evaluation execution order

When <Import/>ing a .props file, ProjectDir is unset (but SolutionDir is set, if applicable). Use MSBuildProjectDirectory. Note that the latter doesn't include a trailing slash.

String.GetHashCode stability

The GetHashCode implementation for strings does not reflect the string's contents, and as such, the hash not stable between program instances.

It seems that Guid's implementation is stable across instances, and even across Mono and .NET 6+ implementations. It also gives 0 for Guid.Empty which is nice.

System.Drawing.SystemIcons rendered

Docs for SystemIcons don't include any pictures, so here they are (Win10, Mono 6.12.x):

SystemIcons_Win10 SystemIcons_Mono

Notice also the default window icon (Form.Icon): on Windows, it's a distinct icon; on Mono, it resembles SystemIcon.Application (not shown in the screenshot). From 2.9, EmuHawk overrides the default.

Type casting

There are two types of casts in C#: the C-style (T) o throws if the object is not of the desired type, whereas o as T evaluates to null if it's not of the desired type. There's no '?' in this null-producing operator (this is probably only confusing if you use Kotlin).

If an object being the wrong type is exceptional—the method can't handle it gracefully—then throw an exception straight away. Having it reported as an NRE when there's no null in sight just delays debugging the problem.

Type constraints (where clauses)

class in where clauses does not mean "not abstract", it means "reference type". Similarly, struct means "value type". There's a lot of complexity re: nullability, so check the docs if you're writing a generic method.

TODO euler diagram

WinForms Control.ResumeLayout footgun

// works
groupBox.ResumeLayout(performLayout: false);
groupBox.PerformLayout();
// breaks subtly
groupBox.ResumeLayout(performLayout: true);