Table of Contents

Struct Error

Namespace
Badeend
Assembly
Badeend.Error.dll

A lightweight immutable error representation that contains:

  • A human-readable error description. (Message)
  • (Optional) A custom data payload, used to provide additional context beyond the message. (Data)
  • (Optional) An inner error, used to build up a "chain" of context. (InnerError)
public readonly struct Error : IEquatable<Error>, IComparable<Error>, IComparable
Implements
Inherited Members

Remarks

This Error type is designed to be a close relative to the built-in Exception class, but with a focus on being lightweight and suitable for situations where errors need to be reported frequently and/or where performance is critical.

The four primary methods for creating new errors are:

All of these are O(1) and allocation free.

This type is designed to be used with Badeend.Result, though it can be used standalone as well. Note that you should generally not attempt to derive any semantic meaning from the Error's content. I.e., Result<T, Badeend.Error> (or its shorthand Result<T>) is semantically the same as Result<T, void> in that: all that the domain logic should care about is whether the operation succeeded or failed. The Error data is just a way to carry additional developer-oriented context.

This type has the size of just a single machine word (4 or 8 bytes), making it a good fit for applications where errors are treated as first-class values, are copied frequently and are propagated through regular control flow patterns instead of stack unwinding.

This type does not collect stack traces by design. Any additional context that you want to attach along the way must be added manually by wrapping it inside a new error using one of constructors that take an InnerError parameter, e.g. Error(string?, object?, Error?).

The default Error contains only a predefined default message and is equivalent to using the parameterless constructor.

Constructors

Error()

Create a new empty Error.

[Pure]
public Error()

Remarks

Errors created by this constructor can be used as a "marker" to signal that an operation did not succeed even in the absence of a descriptive message.

This is an O(1) operation, does not allocate any memory and is equivalent to the default value.

Error(IError?)

Create a new Error using the provided error as the backing implementation.

[Pure]
public Error(IError? error)

Parameters

error IError

Remarks

This is an O(1) operation and does not allocate any memory.

Error(Exception?)

Create a new Error from the provided exception.

[Pure]
public Error(Exception? exception)

Parameters

exception Exception

Remarks

If the provided exception was obtained through AsException(), the original Error is returned to prevent double wrapping.

Otherwise, this is functionally equivalent to creating an Error with:

Error(string?)

Create a new Error with the provided message.

[Pure]
public Error(string? message)

Parameters

message string

Remarks

This is an O(1) operation and does not allocate any memory.

Error(string?, Error?)

Create a new Error with the provided message that wraps the innerError.

[Pure]
public Error(string? message, Error? innerError)

Parameters

message string
innerError Error?

Error(string?, object?, Error?)

Create a new Error with the provided message and/or data that wraps the innerError.

[Pure]
public Error(string? message, object? data = null, Error? innerError = null)

Parameters

message string
data object
innerError Error?

Properties

Data

The payload attached at this specific point in the error chain.

[Pure]
public object? Data { get; }

Property Value

object

Remarks

Generally, you should not depend on specific payloads existing at specific levels in the error chain as they may change over time due to e.g. internal refactorings or other updates to the code that produces the errors.

If you need to retrieve a specific type of payload, consider using the TryFindData<T>(out T) method instead.

InnerError

Gets the inner error associated with the current Error instance, or null if this is a "root" error.

[Pure]
public Error? InnerError { get; }

Property Value

Error?

Remarks

This property is similar to the InnerException property of regular .NET exceptions. When a new Error is created by using e.g. Error(string?, object?, Error?), the pre-existing Error instance becomes the InnerError of the new instance. This chaining allows for capturing contextual information at each layer where the error is encountered, while retaining the original error details.

Accessing InnerError provides a way to traverse the chain of errors in reverse order, from the most recently appended error back to the original root error.

Message

Human-readable description of the error. A generic fallback string will be returned if no message was provided.

[Pure]
public string Message { get; }

Property Value

string

Remarks

Error messages are intended for human consumption only and should not be parsed or relied on programmatically. Parsing this message may lead to breaking changes if the message format changes in the future.

Methods

AsException()

Convert the error into an exception. This may return a previously Error-wrapped-Exception as-is. The returned exception should therefore be considered as "already thrown" and should not be thrown directly again. The only supported method for throwing the returned value is as the inner exception of a fresh exception instance.

[Pure]
public Exception AsException()

Returns

Exception

Remarks

The returned Exception hierarchy is for debugging purposes only. The format is not stable and may change without prior notice.

CompareTo(Error)

Compare two errors.

Errors are compared by their components: (Message, Data, InnerError).

[Pure]
public int CompareTo(Error other)

Parameters

other Error

Returns

int

See IComparable<T>.CompareTo(T) for more information.

Exceptions

ArgumentException

The Data object does not implement IComparable.

Equals(Error)

Check two Error instances for equality. Errors use structural equality and are considered "equal" when their (Message, Data, InnerError) components are equal. The Data component is compared using the Equals(object) method.

[Pure]
public bool Equals(Error other)

Parameters

other Error

Returns

bool

FromEnum<TEnum>(TEnum)

Create a new Error from the provided enum value.

public static Error FromEnum<TEnum>(TEnum value) where TEnum : struct, Enum

Parameters

value TEnum

Returns

Error

Type Parameters

TEnum

Remarks

The error message can be customized by annotating the enum members with the [ErrorMessage] attribute.

If the value is a regular declared enum member (i.e. it is returned by Enum.GetValues), then this is an O(1) operation and does not allocate any memory.

GetHashCode()

[Pure]
public override int GetHashCode()

Returns

int

ToString()

Get a string representation of the error for debugging purposes. The format is not stable and may change without prior notice.

[Pure]
public override string ToString()

Returns

string

TryFindData<T>(out T)

Search through the error chain and attempt to retrieve the payload that matches the specified type T.

public bool TryFindData<T>(out T data)

Parameters

data T

Returns

bool

Type Parameters

T

The type of the payload object to retrieve from the Error.

Remarks

This method provides a type-safe way to access metadata without overly relying on the order in which the errors are nested. If multiple items of type T exist, the top-most instance in the chain is returned.

Operators

operator ==(Error, Error)

Check two Error instances for equality. Errors use structural equality and are considered "equal" when their (Message, Data, InnerError) components are equal. The Data component is compared using the Equals(object) method.

[Pure]
public static bool operator ==(Error left, Error right)

Parameters

left Error
right Error

Returns

bool

operator !=(Error, Error)

Check for inequality. See Equals(Error) for more info.

[Pure]
public static bool operator !=(Error left, Error right)

Parameters

left Error
right Error

Returns

bool