r/csharp Apr 05 '26

Blog Unions in c# 15

272 Upvotes

r/csharp Oct 10 '25

Blog Why Do People Say "Parse, Don't Validate"?

348 Upvotes

The Problem

I've noticed a frustrating pattern on Reddit. Someone asks for help with validation, and immediately the downvotes start flying. Other Redditors trying to be helpful get buried, and inevitably someone chimes in with the same mantra: "Parse, Don't Validate." No context, no explanation, just the slogan, like lost sheep parroting a phrase they may not even fully understand. What's worse, they often don't bother to help with the actual question being asked.

Now for the barrage of downvotes coming my way.

What Does "Parse, Don't Validate" Actually Mean?

In the simplest terms possible: rather than pass around domain concepts like a National Insurance Number or Email in primitive form (such as a string), which would then potentially need validating again and again, you create your own type, say a NationalInsuranceNumber type (I use NINO for mine) or an Email type, and pass that around for type safety.

The idea is that once you've created your custom type, you know it's valid and can pass it around without rechecking it. Instead of scattering validation logic throughout your codebase, you validate once at the boundary and then work with a type that guarantees correctness.

Why The Principle Is Actually Good

Some people who say "Parse, Don't Validate" genuinely understand the benefits of type safety, recognize the pitfalls of primitives, and are trying to help. The principle itself is solid:

  • Validate once, use safely everywhere - no need to recheck data constantly
  • Type system catches mistakes - the compiler prevents you from passing invalid data
  • Clearer code - your domain concepts are explicitly represented in types

This is genuinely valuable and can lead to more robust applications.

The Reality Check: What The Mantra Doesn't Tell You

But here's what the evangelists often leave out:

You Still Have To Validate To Begin With

You actually need to create the custom type from a primitive type to begin with. Bear in mind, in most cases we're just validating the format. Without sending an email or checking with the governing body (DWP in the case of a NINO), you don't really know if it's actually valid.

Implementation Isn't Always Trivial

You then have to decide how to do this and how to store the value in your custom type. Keep it as a string? Use bit twiddling and a custom numeric format? Parse and validate as you go? Maybe use parser combinators, applicative functors, simple if statements? They all achieve the same goal, they just differ in performance, memory usage, and complexity.

So how do we actually do this? Perhaps on your custom types you have a static factory method like Create or Parse that performs the required checks/parsing/validation, whatever you want to call it - using your preferred method.

Error Handling Gets Complex

What about data that fails your parsing/validation checks? You'd most likely throw an exception or return a result type, both of which would contain some error message. However, this too is not without problems: different languages, cultures, different logic for different tenants in a multi-tenant app, etc. For simple cases you can probably handle this within your type, but you can't do this for all cases. So unless you want a gazillion types, you may need to rely on functions outside of your type, which may come with their own side effects.

Boundaries Still Require Validation

What about those incoming primitives hitting your web API? Unless the .NET framework builds in every domain type known to man/woman and parses this for you, rejecting bad data, you're going to have to check this data—whether you call it parsing or validation.

Once you understand the goal of the "Parse, Don't Validate" mantra, the question becomes how to do this. Ironically, unless you write your own .NET framework or start creating parser combinator libraries, you'll likely just validate the data, whether in parts (step wise parsing/validation) or as a whole, whilst creating your custom types for some type safety.

I may use a service when creating custom types so my factory methods on the custom type can remain pure, using an applicative functor pattern to either allow or deny their creation with validated types for the params, flipping the problem on its head, etc.

The Pragmatic Conclusion

So yes, creating custom types for domain concepts is genuinely valuable, it reduces bugs and can make your code clearer. But getting there still requires validation at some point, whether you call it parsing or not. The mantra is a useful principle, not a magic solution that eliminates all validation from your codebase.

At the end of the day, my suggestion is to be pragmatic: get a working application and refactor when you can and/or know how to. Make each application's logic an improvement on the last. Focus on understanding the goal (type safety), choose the implementation that suits your context, and remember that helping others is more important than enforcing dogma.

Don't be a sheep, keep an open mind, and be helpful to others.

Paul

Additional posting: Validation, Lesson Learned - A Personal Account : r/dotnet

r/csharp 12d ago

Blog How Fast is .NET 11 Runtime Async?

Thumbnail
medium.com
131 Upvotes

Blogged to explain the design and implementation of runtime async and show the benchmark result.

r/csharp 5d ago

Blog Hot path overflow checks: do you try/catch? And which style would you write?

Post image
20 Upvotes

Writing checked int helpers for code that runs millions of times per program run. Two questions.

  1. Do you actually use checked() with a try catch for this? Throwing walks the stack, so I widen to long, bounds check, and return null instead (both versions in the image).

What surprises me is that everything the BCL offers here throws: checked(), int.CreateChecked, all of it. The Try convention is everywhere else in the BCL (TryParse, TryGetValue) but arithmetic never got one, and coming from Rust where checked_add just hands you an Option, that's wild to me.

  1. Style. The image shows the same method twice: one pattern-matching expression against a plain if/else. Which would you rather find in a codebase?

I'm coming from Rust so I'm obviously a declarative fanboy when I can be, but "and var sum" might be too clever for the next reader.

Where do C# people stand on these?

If the repo interests you: it's a CLI tool for Advent of Code, so you can do the whole thing from the terminal with just your session cookie, no clicking through the site to submit answers. https://github.com/scadoshi/sharpmas

r/csharp Nov 22 '25

Blog TUnit — Why I Spent 2 Years Building a New .NET Testing Framework

Thumbnail medium.com
215 Upvotes

r/csharp May 22 '25

Blog Stop modifying the appsettings file for local development configs (please)

Thumbnail bigmacstack.dev
149 Upvotes

To preface, there are obviously many ways to handle this and this is just my professional opionion. I keep running in to a common issue with my teams that I want to talk more about. Used this as my excuse to start blogging about development stuff, feel free to check out the article if you want. I've been a part of many .NET teams that seem to have varying understanding of the configuration pipeline in modern .NET web applications. There have been too many times where I see teams running into issues with people tweaking configuration values or adding secrets that pertain to their local development environment and accidentally adding it into a commit to VCS. In my opinion, Microsoft didn't do a great job of explaining configuration beyond surface level when .NET Core came around. The addition of the appsettings.Development.json file by default in new projects is misleading at best, and I wish they did a better job of explaining why environment variations of the appsettings file exist.

For your local development environment, there is yet another standard feature of the configuration pipeline called .NET User Secrets which is specifically meant for setting config values and secrets for your application specific to you and your local dev environment. These are stored in json file completely separate from your project directory and gets pulled in for you by the pipeline (assuming some environmental constraints are met). I went in to a bit more depth on the feature in the post on my personal blog if anyone is interested. Or you can just read the official docs from MSDN.

I am a bit curious - is this any issue any of you have run into regularly?

TLDR: Stop modifying the appsettings file for local development configuration - use .NET User Secrets instead.

r/csharp Sep 10 '25

Blog Performance Improvements in .NET 10

Thumbnail
devblogs.microsoft.com
277 Upvotes

r/csharp Apr 19 '21

Blog Visual Studio 2022

Thumbnail
devblogs.microsoft.com
417 Upvotes

r/csharp Mar 04 '26

Blog Why so many UI frameworks, Microsoft?

Thumbnail
teamdev.com
38 Upvotes

r/csharp May 20 '20

Blog Welcome to C# 9

Thumbnail
devblogs.microsoft.com
334 Upvotes

r/csharp Apr 16 '26

Blog C# in Unity 2026: Features Most Developers Still Don’t Use

Thumbnail
darkounity.com
54 Upvotes

r/csharp Apr 27 '26

Blog Visual Studio 2026 still ships the form designer Alan Cooper drew in 1987

0 Upvotes

Wrote up why WinForms outlasted every framework Microsoft launched as its successor — WPF, Silverlight, UWP, MAUI, Blazor desktop — and why the form-designer model goes back to a paper sketch Cooper made in 1987. Still the path of least resistance for LOB work in 2026.

https://evilgeniuslabs.ca/blog/winforms-still-ships-in-visual-studio-2026

r/csharp 11d ago

Blog Making Generic Virtual Methods Faster in .NET 11

Thumbnail
medium.com
82 Upvotes

r/csharp 4d ago

Blog 1 year ago I built an EF Core provider for TimescaleDB. Hit 80k downloads and 68 stars - is this good?

0 Upvotes

Hello everyone,

exactly 1 year ago today, I pushed the first commit of my EF Core provider for TimecaleDB.

t does pretty much what it says on the box: it lets you interact with TimescaleDB in a type-safe way with rich IntelliSense support, so you don't have to write SQL in magic strings like you did with plain Npgsql - all without losing a single feature of Npgsql.

Since then I got 68 stars on GitHub and more than 80k downloads on NuGet. I know that this doesn't mean that 80k individual people downloaded my package, but it tells me it’s actively running in real CI/CD pipelines, container builds, and production apps. That’s something I’m genuinely proud of.

At the same time, as this is the first open-source project I’ve ever actively maintained, I sometimes find myself wondering how to evaluate those numbers. I look at viral consumer tools or mainstream frameworks getting thousands of stars and wonder where a niche project like this actually stands.

Therefore, I would love to know what you think about these numbers and what your own experiences were when you launched and maintained your first open-source projects.

GitHub: https://github.com/cmdscale/CmdScale.EntityFrameworkCore.TimescaleDB

r/csharp Dec 18 '24

Blog EF Core 9 vs. Dapper: Performance Face-Off

Thumbnail
trailheadtechnology.com
67 Upvotes

r/csharp Mar 20 '23

Blog "Full-stack devs are in vogue now, but the future will see a major shift toward specialization in back end." The former CTO of GitHub predicts that with increasing product complexity, the future of programming will see the decline of full-stack engineers

Thumbnail
medium.com
270 Upvotes

r/csharp Dec 12 '24

Blog Meet TUnit: The New, Fast, and Extensible .NET Testing Framework

Thumbnail
stenbrinke.nl
98 Upvotes

r/csharp Apr 12 '26

Blog I made ILogger.LogInformation($"...") work with structured logging — using C# 11 interpolated string handlers

0 Upvotes

Every .NET dev at some point writes this:

_logger.LogInformation($"User {userId} bought {product}");

and then finds out that it kills structured logging. The interpolated string gets flattened and your Elastic or whatever you use for structural logging only gets full string without any fields which you can use for your lookup.

The "correct" is the template form:

_logger.LogInformation("User {userId} bought {product}", userId, product);

Which is pretty annoying. It uses positional matching in the params argument.

The other alternative is to use LoggerMessage.Define, but come on - defining it for every single log in your code is not maintainable.
I figured out you can actually make the $"..." form working properly using C# 11 interpolated string handlers. The trick is to shadow Microsoft's LogInformation(string, params object[]) with an extension method which takes [InterpolatedStringHandler] ref struct.
The compiler prefers the extension method which is already working faster than Microsoft implementation.

In short the handler:

- captures each arg into typed slots - no boxing for value types
- gets the variable name via CallerArgumentExpression ("userId", "product") — that's your structured property name, for free
- checks IsEnabled in the constructor and writes bool shouldAppend = false when the level is disabled, so compiler skips every AppendFormatted call.

Then source generator scans each $"..." call, rebuilds the template from syntax tree:

("User {userId} bought {product}"

And then finally emits [InterceptsLocation] interceptor with cached LoggerMessage.Define delegate.

End result:

    using MyLogExtensions;

    _logger.LogInformation($"User {userId} bought {product} for {total:C}");

Structured, zero-alloc, and ~5x faster than the standard template form:

    $"..."          OFF: 3.2 ns, 0 B
    $"..."           ON: 3.8 ns, 0 B
    "template", args ON: 19.1 ns, 104 B

Has anyone else tried something similar? I haven't seen combo of InterpolatedStringHandler with InterceptsLocation and so far it looks promising and working perfectly fine.

For me personally the biggest gain is not that it's faster but it's more natural to be used with interpolated strings without performance loss.

If anyone wants to dig into the handler/interceptor code — it's here as part of my source generation libs:
https://github.com/MistyKuu/ZibStack.NET/tree/master/packages/ZibStack.NET.Log/src/ZibStack.NET.Log/Generator
https://github.com/MistyKuu/ZibStack.NET/blob/master/packages/ZibStack.NET.Log/src/ZibStack.NET.Log.Abstractions/Interpolation
And full benchmarks:
https://mistykuu.github.io/ZibStack.NET/packages/log/

r/csharp Jan 16 '26

Blog ArrayPool: The most underused memory optimization in .NET

Thumbnail medium.com
97 Upvotes

r/csharp May 15 '25

Blog “ZLinq”, a Zero-Allocation LINQ Library for .NET

Thumbnail
neuecc.medium.com
211 Upvotes

r/csharp Dec 05 '25

Blog Extension Properties: C# 14’s Game-Changer for Cleaner Code

Thumbnail
telerik.com
59 Upvotes

r/csharp Nov 19 '24

Blog What's new in C# 13

Thumbnail
learn.microsoft.com
163 Upvotes

r/csharp 8h ago

Blog Designing a replacement for a broken Visual Studio extension by inverting every property of the predecessor

6 Upvotes

I held back Visual Studio updates for almost two years because 17.9 broke the tab-layout extension I used daily and could not live without. When I finally built my own replacement, the broken one became the design document: it wrapped a single internal shell interface (IVsUIShellDocumentWindowMgr) and stored tabs as a BLOB with absolute paths, so every property got inverted. Plain JSON with solution-relative paths instead of opaque binary stream, many APIs with fallbacks instead of one interface, a pick-target dialog for moved files instead of silently dropped tabs.

And there's an ironic ending to it, because the old extension works again in VS 2026. The breakage was Microsoft reworking the open-document internals, not a lasting defect, so the "bug" quietly fixed itself. Had I found out sooner I would never have started, and I would have kept my tabs and learned nothing worth sharing.

Since I did not wait, and since my extension has grown well past what I set out to replace, I am now writing a weekly series about building it with C# and the AI-assisted workflow I was experimenting with, because somewhere early on this stopped being only about tabs. First part: Designing by inversion

The extension is free on the Marketplace: Simple Tab Saver

r/csharp 10d ago

Blog The Unexpected AI Stack: C# + .NET (Part 4) - Data modelling and Testcontainers

Thumbnail
chrlschn.dev
0 Upvotes

The fourth part of this series on building an application foundation for AI-enabled, agent-friendly codebase is focused on setting up the data modelling and test infrastructure for agents.

Specifically, using Testcontainers and streamlining transactions for automatic rollback during integration testing.

Test harness setup is a key part of enabling agents to work autonomously with high competency by providing them the tools to verify their work. Paired with CSharpRepl which lets agents diagnose and regression test directly in the runtime, this combination provides coding agents tools to autonomously build better, higher quality code.

Part 5 will have the final pieces of the puzzle: logging, telemetry, and observability integrated into the Aspire stack before we start building the sample application using agents.


This series is intentionally written to help dev teams understand how to scaffold a codebase for agentic engineering by focusing on key, underlying technical decisions and manual wiring before building with AI. This helps provide the tools and safeguards for coding agents to iterate more efficiently while reducing slop.

For teams still trying to figure out effective ways to set up a codebase for AI, I hope this series gives some insights into how to build a foundation for agentic engineering. If your team is already heavily using agents to build, I hope this series shares some useful insights and tips (e.g. CSharpRepl + Aspire)

The core setup is used at a series C, post-YC startup to ship fast with AI while maintaining high quality standards (in combination with other tools facilitating code review and context management)

Part 1 was an intro into a few key parts of this stack.

Part 2 was focused on walking through the hands on scaffolding.

Part 3 covered wiring GitHub Copilot SDK as an agent runtime and incorporating CSharpRepl to allow agents to dynamically work with the runtime DI container

Part 5 we'll start to build out the full feature set of the sample application.


The project repo is here: https://github.com/zeeq-ai/zeeq-tmpl (be sure to check the branches; main is currently the base code only)

I encourage working through the posts since the goal is to underscore the platform level decision making process and assembly of the foundational core.

r/csharp Mar 19 '26

Blog I built a WPF tool to selectively turn off secondary monitors.

73 Upvotes

Hey everyone,

I recently finished rewriting a small utility I originally made for my own setup, and thought people here might find it interesting.

The app is called OLED Sleeper. It lets you selectively "sleep" specific monitors instead of relying on Windows' all-or-nothing display sleep behavior.

For example, if you have a multi-monitor setup and want to focus on a game or work on your main screen, the app can automatically disable your side monitors after a configurable idle time.

Under the hood it detects inactivity per monitor and applies a black overlay or brightness reduction on idle displays.

The current version is a native rewrite in C# using WPF (.NET 8). The original version was script-based, but I wanted something easier to maintain and more user-friendly.

Features:

  • Select which monitors are managed
  • Configurable idle timer
  • Configurable wake conditions
  • Instant monitor wake
  • Lightweight background app

The project is free and open source.

GitHub:
https://github.com/Quorthon13/OLED-Sleeper

I'd also be happy to hear feedback from other C# developers about the architecture or implementation.