<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg" -->

---
title: Result Pattern in C# and .NET 10 - When to Use, When to Skip
description: A deep-dive walks through implementing the Result pattern in C# and .NET 10 for a Minimal API: building a Result<T> struct, mapping errors to RFC 9457...
canonical: https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Result Pattern in C# and .NET 10 - When to Use, When to Skip | daily.dev
og:description: A deep-dive walks through implementing the Result pattern in C# and .NET 10 for a Minimal API: building a Result<T> struct, mapping errors to RFC 9457...
og:url: https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg
og:image: https://api.daily.dev/og/posts/qwYHjumGG.png
og:image:alt: Result Pattern in C# and .NET 10 - When to Use, When to Skip
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Result Pattern in C# and .NET 10 - When to Use, When to Skip

**[Code with Mukesh](https://daily.dev/sources/codewithmukesh)** · [@iammukeshm](https://daily.dev/iammukeshm) · 26 min read · 47 upvotes · 1 comments

## Summary

A deep-dive walks through implementing the Result pattern in C# and .NET 10 for a Minimal API: building a Result<T> struct, mapping errors to RFC 9457 ProblemDetails, wiring it to async EF Core services, and testing it. BenchmarkDotNet measurements on .NET 10.0.11 show a thrown/caught exception costs ~1.11 microseconds at depth 1 and ~3.67 microseconds at depth 10, versus under 9 nanoseconds for a Result return, but this only matters at scale (e.g., bulk validation loops), not typical API failure rates. Six practical gotchas are covered: Results can be silently ignored, stack traces are lost, the pattern spreads through the call stack, async chaining is awkward, collections need careful typing, and third-party throws (EF Core, HttpClient) still require a global exception handler. The piece also compares libraries (ErrorOr, FluentResults, Ardalis.Result, CSharpFunctionalExtensions, OneOf) and previews how C# 15 union types (shipping with .NET 11, expected November 2026) will let a compiler-checked union replace the hand-written Result type.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://codewithmukesh.com/blog/result-pattern-dotnet>

## Questions this post answers

### How much faster is returning a Result compared to throwing an exception in .NET 10?

A Result return costs under 9 nanoseconds while a thrown and caught exception costs about 1.11 microseconds at one stack frame deep and 3.67 microseconds at ten frames deep, measured with BenchmarkDotNet on .NET 10.0.11. That is roughly 1,500 times slower at depth 1, but at typical API failure rates (a few hundred per second) the absolute difference is invisible; it only matters when failures happen thousands of times inside a loop.

_Developers weighing exceptions versus result types for hot-path error handling can track benchmarks like these on daily.dev._

### Does CoreCLR's exception handling performance change in .NET 9 affect Result pattern benchmarks?

Yes, CoreCLR replaced its exception handling implementation in .NET 9 with the model from NativeAOT, which Microsoft describes as 2-4 times faster per some exception handling micro-benchmarks, enabled by default everywhere except Windows x86. This means older articles claiming huge exception overhead were measured against a slower, now-outdated implementation.

_Teams deciding whether exception cost still justifies avoiding throws can follow runtime performance changes like this on daily.dev._

### Will C# 15 union types replace the need for a hand-written Result type?

They replace the hand-written implementation but not the underlying pattern. C# 15 ships with .NET 11, whose final release Microsoft expects in November 2026, and lets a union declare a value as exactly one of a fixed set of case types with compiler-checked exhaustive switch matching, unlike a hand-rolled Result<T> where nothing stops reading .Value without checking .IsSuccess first.

_Developers planning a migration path for error-handling code can watch for union type updates via daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@zalarian** · 0 upvotes

> This is how functional languages, including F#, handle exceptions. I think it's also a more correct way to handle exceptions. Promoting the error states into types gets you compile-time type checking for accessing bad states. It's not perfect, but you get way more guarantees than if you were throwing exceptions. I really hope .Net really starts to adopt this approach to error handling because it's my biggest complaint about the platform. I also like your point about performance. It is the weakest argument. It should be about _correctness_. It doesn't matter if you can give the the wrong...

## Similar posts on daily.dev

- [Best Practices for Exceptions in ASP.NET Core](https://daily.dev/posts/best-practices-for-exceptions-in-asp-net-core-eews3z8nt) · Telerik · 20 upvotes · 2 comments
- [Result is the most boring sum type](https://daily.dev/posts/result-is-the-most-boring-sum-type-jtvdlei3c) · ploeh blog · 1 upvotes · 0 comments
- [Rocky Jaiswal](https://daily.dev/posts/rocky-jaiswal-5z3kim9vn) · Hacker News · 1 upvotes · 0 comments

---

Tags: [#c#](https://daily.dev/tags/c#), [#aspnet](https://daily.dev/tags/aspnet)

[View this post on daily.dev](https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Result Pattern in C# and .NET 10 - When to Use, When to Skip","url":"https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg"},"datePublished":"2026-09-28T08:46:33.887Z","dateModified":"2026-09-29T05:00:15.999Z","description":"A deep-dive walks through implementing the Result pattern in C# and .NET 10 for a Minimal API: building a Result<T> struct, mapping errors to RFC 9457...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/16196be9147d8cb1f17ba7f85c0c10a4?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/16196be9147d8cb1f17ba7f85c0c10a4?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Code with Mukesh","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Person","name":"Mukesh Murugan","url":"https://daily.dev/iammukeshm","image":"https://lh3.googleusercontent.com/a-/AFdZucr2UBIpOeVTWohK8XKuXPOutNG6hgyQMz7CYj7LEA=s100","interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":810}},"commentCount":1,"discussionUrl":"https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":47},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"c#,aspnet","timeRequired":"PT26M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Code with Mukesh","item":"https://daily.dev/sources/codewithmukesh"},{"@type":"ListItem","position":3,"name":"Result Pattern in C# and .NET 10 - When to Use, When to Skip"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg","comment":[{"@type":"Comment","text":"This is how functional languages, including F#, handle exceptions. I think it’s also a more correct way to handle exceptions. Promoting the error states into types gets you compile-time type checking for accessing bad states. It’s not perfect, but you get way more guarantees than if you were throwing exceptions. I really hope .Net really starts to adopt this approach to error handling because it’s my biggest complaint about the platform. I also like your point about performance. It is the weakest argument. It should be about correctness. It doesn’t matter if you can give the the wrong answer fast.","datePublished":"2026-09-29T14:45:41.041Z","dateModified":"2026-09-29T14:47:08.554Z","url":"https://daily.dev/posts/qwYHjumGG#c-kxWw3a29y","author":{"@type":"Person","name":"zalarian","url":"https://daily.dev/zalarian","image":"https://avatars.githubusercontent.com/u/19542063?v=4"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/result-pattern-in-c-and-net-10---when-to-use-when-to-skip-qwyhjumgg#faq","mainEntity":[{"@type":"Question","name":"How much faster is returning a Result compared to throwing an exception in .NET 10?","acceptedAnswer":{"@type":"Answer","text":"A Result return costs under 9 nanoseconds while a thrown and caught exception costs about 1.11 microseconds at one stack frame deep and 3.67 microseconds at ten frames deep, measured with BenchmarkDotNet on .NET 10.0.11. That is roughly 1,500 times slower at depth 1, but at typical API failure rates (a few hundred per second) the absolute difference is invisible; it only matters when failures happen thousands of times inside a loop. Developers weighing exceptions versus result types for hot-path error handling can track benchmarks like these on daily.dev."}},{"@type":"Question","name":"Does CoreCLR's exception handling performance change in .NET 9 affect Result pattern benchmarks?","acceptedAnswer":{"@type":"Answer","text":"Yes, CoreCLR replaced its exception handling implementation in .NET 9 with the model from NativeAOT, which Microsoft describes as 2-4 times faster per some exception handling micro-benchmarks, enabled by default everywhere except Windows x86. This means older articles claiming huge exception overhead were measured against a slower, now-outdated implementation. Teams deciding whether exception cost still justifies avoiding throws can follow runtime performance changes like this on daily.dev."}},{"@type":"Question","name":"Will C# 15 union types replace the need for a hand-written Result type?","acceptedAnswer":{"@type":"Answer","text":"They replace the hand-written implementation but not the underlying pattern. C# 15 ships with .NET 11, whose final release Microsoft expects in November 2026, and lets a union declare a value as exactly one of a fixed set of case types with compiler-checked exhaustive switch matching, unlike a hand-rolled Result<T> where nothing stops reading .Value without checking .IsSuccess first. Developers planning a migration path for error-handling code can watch for union type updates via daily.dev."}}]}
```

