Petr Volobuev | Technology RadarPetr Volobuev | Technology Radar
Using

C# 14 with .NET 10. Waiting for this LTS as the next baseline version for all projects.

The main feature I've been waiting for is the field keyword for property accessors. Finally you can write a check or a computation in a getter/setter without explicitly declaring a backing field. The classic private string _name pattern is becoming a thing of the past for the typical cases.

Other things on my radar:

  • Extension types — the new extension block syntax as an alternative to extension methods. Lets you declare properties and operators for types you don't own, not just methods. Still figuring out how best to apply it
  • Improvements around Span<T> and params — the language increasingly lets you write high-performance code without dropping into unsafe

The version is still in active development as I write this, but the overall direction is clear — the language is maturing and shedding the remaining boilerplate.

Using

C# 13 with .NET 9. Not an LTS release, and there aren't many language changes, but some are pleasant.

  • params collectionsparams now works not only with arrays but also with IEnumerable<T>, Span<T> and other collections. At last you can write universal methods without a pile of overloads
  • the new System.Threading.Lock type — a replacement for the marker object in lock. Same semantics, but it expresses intent more clearly
  • partial properties and indexers — extends the partial pattern for source generators, which we're using more and more
  • the \e escape sequence for the ESC character — a small thing for console utilities, but nice.

Overall C# 13 feels like polishing rather than a big leap — my main expectations have already shifted to .NET 10.

What stuck right away: params collections and, partly, System.Threading.Lock, though I haven't yet felt where its strength lies compared to plain dummy objects.

Using

C# 12 with .NET 8. Two new features went straight into everyday work.

Primary constructors — we've been waiting for these on regular classes (not just records) for ages. Constructor dependencies are now declared right in the class header, less boilerplate in services. Though it takes a little getting used to that a parameter doesn't automatically become a field — if you need to keep it, you capture it explicitly.

Collection expressions[1, 2, 3], the spread operator .. for merging collections. Finally the syntax is no worse than in other languages. Plays nicely with Span and ReadOnlySpan without extra allocations.

Other goodies:

  • using aliases can now point to any types, not just named types — using Point = (int X, int Y) and the like
  • default parameters in lambdas — it's now easier to pass lambdas into places that need compatibility with several signatures

What a banger of a release!

Using

C# 10 with .NET 6. The language has set course for brevity — every release strips away a little more noise.

  • file-scoped namespace — removed one level of indentation across every file. A small thing, but the eye rejoices instantly
  • global using — moved the standard namespaces into a single file and stopped seeing identical blocks of usings everywhere
  • record struct — everything I love about record, but as a value type. Came in handy where boxing is unwelcome
  • CallerArgumentExpression — looks great for validation helper methods, though I haven't found many uses yet
  • extended property patterns — you can now write x is { Foo.Bar: not null } instead of the nested is { Foo: { Bar: ... } }
Using

C# 9 together with .NET 5. The big discovery is record. Finally, an immutable type with value equality out of the box, without hand-rolling Equals/GetHashCode. Found a use for it right away in domain objects and DTOs.

Other things I liked:

  • init-only properties — one more step toward immutability without extra ceremony
  • new() — target-typed new, less type repetition
  • pattern matching grew up: is not, and/or combinations in switch — genuinely more expressive now
  • top-level statements — appreciated them in small utilities and scripts

Nullable reference types technically appeared in C# 8, but only now have I really started turning on nullable enable and dealing with the warnings instead of switching them off.

Using

async/await enters my life. To understand how it actually works, I discover utilities for inspecting IL code.

Up to this point, async execution for me meant either BackgroundWorker (WinForms), ready-made API methods (the BeginSomething/EndSomething kind), or Tasks with ContinueWith.

And multithreading on .net in general. Before this, the only multithreading I'd touched was back at university, writing programs for a supercomputer cluster.

Along with all of the above come tasks involving synchronization primitives, mostly lock (monitor) and ManualResetEvent

Using

In the university algorithms course I started actively using generics, by analogy with template classes in C++.

Also getting a basic understanding of bytecode, the JIT compiler, the CLR and the Garbage Collector.

Using

Got the idea behind the language. Started to believe in OOP. Discovered delegates and events.

Assessing

Discovered the C-four-pluses language. Everyone says it's super cool, but to me it's confusing and awkward. Still, some gigs require it, so I have to figure it out.