Skip to content

Latest commit

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

"Buy Me A Coffee"

Types.Result

NuGet VersionNuGet DownloadsTwitter

A minimal Result / Result<TError> for library authors who want to publish a closed, exhaustively-checkable contract of failure modes - with a separate channel for native/platform exceptions. No combinators, no extensibility hooks - the library defines its failure surface, the consumer reacts.

Why this exists

Most Result libraries (FluentResults, ErrorOr, Ardalis.Result) are designed for application-level error pipelines: open polymorphic errors, combinators (Map / Bind / Match), reasons / metadata chains. That's the wrong shape for a library boundary type, where the calls:

  • have a fixed, documented set of failure modes (good fit for an enum),
  • can also throw raw platform/SDK exceptions that the library can't fully classify,
  • are translated by the consumer at the boundary, not pipelined deeper.

This package occupies that niche.

Install

dotnet add package Kebechet.Types.Result

Types in this package

TypeWhen to use
ResultLibrary call that returns no value; only failure is "it threw."
Result<TError>Library call that returns no value; closed enum of documented failures + native exception channel.
DataResult<TValue>Library call that returns a value; only failure is "it threw."
DataResult<TValue, TError>Library call that returns a value; closed enum of documented failures + native exception channel.

The non-generic Result types and the DataResult types can also be subclassed to give per-operation return types named docs (e.g. WriteHealthDataResult : Result<WriteError> carrying its own RecordIds property). Use the generic DataResult directly for simple cases; subclass when you want a self-documenting return type.

Usage

Exception-only outcome

When the call has only one failure shape - "it threw":

usingTypes.Result;publicclassConnectResult:Result{publicstring?SessionId{get;init;}}publicConnectResultConnect(){try{varsession=_native.OpenSession();returnnewConnectResult{SessionId=session.Id};}catch(Exceptionex){returnnewConnectResult{ErrorException=ex};}}

Typed enum errors plus exception channel

When the library has a closed set of documented failure modes and also needs to surface raw platform exceptions:

usingTypes.Result;publicenumWriteError{PermissionDenied,SdkUnavailable,QuotaExceeded}publicclassWriteResult:Result<WriteError>{publicIReadOnlyList<string>RecordIds{get;init;}=[];}publicWriteResultWrite(IList<Record>items){if(!_hasPermission){returnnewWriteResult{Error=WriteError.PermissionDenied};}try{varids=_native.Insert(items);returnnewWriteResult{RecordIds=ids};}catch(Exceptionex){returnnewWriteResult{ErrorException=ex};}}

Consumer side:

varresult=library.Write(items);if(result.IsSuccess){Persist(result.RecordIds);return;}if(result.Erroris{}error){varmessage=errorswitch{WriteError.PermissionDenied=>"Grant permission and retry.",WriteError.SdkUnavailable=>"SDK not installed.",WriteError.QuotaExceeded=>"Try again later."};ShowError(message);return;}LogPlatformException(result.ErrorException!);

The switch expression over a WriteError enum is exhaustively checked by the compiler (warning CS8509 - promote to error in your csproj for hard enforcement).

Generic value carrier (no per-operation subclass)

For simple cases where a per-operation type would be overkill:

usingTypes.Result;publicDataResult<int>CountSessions(){try{returnnewDataResult<int>{Value=_native.CountSessions()};}catch(Exceptionex){returnnewDataResult<int>{ErrorException=ex};}}publicDataResult<UserProfile,ProfileError>GetProfile(stringid){if(!_hasPermission){returnnewDataResult<UserProfile,ProfileError>{Error=ProfileError.Forbidden};}try{varprofile=_native.LoadProfile(id);returnnewDataResult<UserProfile,ProfileError>{Value=profile};}catch(Exceptionex){returnnewDataResult<UserProfile,ProfileError>{ErrorException=ex};}}

Reading the value:

varresult=service.GetProfile("abc");if(!result.IsSuccess){HandleFailure(result);return;}varprofile=result.Value!;// safe to dereference once IsSuccess is checked

Value is only meaningful when IsSuccess is true. On failure, reference-typed values are null and value-typed values are default(TValue) - always check IsSuccess first.

Design notes

This packageFluentResults / ErrorOr
Errors are a closed setyes - enumno - open polymorphic objects
Compiler-checked exhaustive matchingyesno
Per-error data fieldsno - enum is just an intyes - subclass Error
Native exception channelyes - first-class peerno - collapsed into a generic error
Combinators (Map, Bind, Match)noyes
Value carrierper-operation subclassResult<T>
Dependenciesnonevaries

If you need rich per-error metadata, error chaining, or pipeline composition, reach for FluentResults or ErrorOr. If you're publishing a library that wants a closed failure contract and a place to put raw platform exceptions, this is the smaller, sharper tool.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages