-
Notifications
You must be signed in to change notification settings - Fork 0
Core Concepts
This page explains the main building blocks of Resultron in simple terms.
In normal C# code, when something fails, you often throw an exception:
public User GetUser(Guid id)
{
var user = _repository.Find(id);
if (user is null)
throw new Exception("User not found");
return user;
}This works, but exceptions have some downsides:
- They are meant for unexpected problems, not everyday business rules (like "user not found").
- They can be slow if used too often.
- The caller must remember to wrap the call in
try/catch, or the app might crash.
Resultron solves this by returning a Result object instead of throwing an exception for expected failures (like validation errors, "not found", etc.).
There are two main types:
Use this when an operation does not return a value, only success or failure. Example: deleting a user, saving data, sending an email.
Result result = Result.Success();
Result result2 = Result.Failure(new Error("Save.Failed", "Could not save the file."));Use this when an operation returns a value on success. T is the type of that value (for example Result<User>, Result<int>, Result<List<string>>).
Result<int> parsed = Result<int>.Success(42);
Result<int> failed = Result<int>.Failure(new Error("Parse.Failed", "Not a number."));Both Result and Result<T> share the same basic properties, because they both inherit from an internal base class:
| Property | Type | Meaning |
|---|---|---|
IsSuccess |
bool |
true if the operation succeeded |
IsFailure |
bool |
Opposite of IsSuccess
|
Error |
Error |
Details about the failure (empty if success) |
Result<T> adds one more property:
| Property | Type | Meaning |
|---|---|---|
Value |
T |
The actual result value (only valid on success) |
Error is a simple record that describes what went wrong:
public sealed record Error(string Code, string? Description = null)
{
public static readonly Error None = new("Error.None");
}-
Code: A short, unique identifier for the error, like"User.NotFound"or"Validation.InvalidEmail". This is useful for checking which error happened in code, or for mapping errors to HTTP status codes in a web API. -
Description: A human-readable message, like"User with id '123' was not found."This is useful for logs or messages shown to users. -
Error.None: A special "no error" value. It is used automatically when aResultis successful.
Many projects create a static class to hold all their error messages, like this:
public static class UserErrors
{
public static Error NotFound(Guid id) =>
new("User.NotFound", $"User with id '{id}' was not found.");
public static Error EmailAlreadyExists(string email) =>
new("User.EmailAlreadyExists", $"A user with email '{email}' already exists.");
public static Error InvalidName =>
new("User.InvalidName", "Name must be at least 2 characters.");
}This keeps your error messages organized and easy to reuse.
Resultron makes sure a Result is never in a broken state. Internally, it checks:
- A successful result must not have an error.
- A failed result must have an error.
If you try to create a broken combination (for example, success with an error), Resultron throws an ArgumentException right away. This protects your code from confusing bugs.
To make code shorter, Resultron allows you to convert an Error directly into a Result (or Result<T>), and a value directly into a Result<T>:
Result result = someError; // same as Result.Failure(someError)
Result<int> result2 = 42; // same as Result<int>.Success(42)
Result<int> result3 = someError; // same as Result<int>.Failure(someError)This is called an implicit conversion. It means you often don't need to write .Success() or .Failure() explicitly — the compiler figures it out for you.
Next: see the full list of methods in Result API Reference and Result API Reference.