Created
May 4, 2024 13:26
-
-
Save IanWold/7efdf5df24bdd4e6ff5c652e1c051d6f to your computer and use it in GitHub Desktop.
Roll Your Own C# Results: https://ian.wold.guru/Posts/roll_your_own_csharp_results.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DatabaseQueryResult<T> | |
{ | |
private enum ResultType | |
{ | |
Found, | |
Empty, | |
ClientError, | |
ServerError | |
} | |
private DatabaseQueryResult() { } | |
private ResultType Type { get; set; } | |
private T? Value { get; set; } | |
private string? ErrorDescription { get; set; } | |
public bool IsFound([NotNullWhen(true)] out T? value) | |
{ | |
value = Value; | |
return Type == DatabaseQueryResultType.Found; | |
} | |
public bool IsError([NotNullWhen(true)] out string? description) | |
{ | |
description = ErrorDescription; | |
return | |
Type == DatabaseQueryResultType.ClientError | |
|| Type == DatabaseQueryResultType.ServerError; | |
} | |
public static DatabaseQueryResult<T> Found(T Value) => new() | |
{ | |
Type = DatabaseQueryResultType.Found | |
Value = value | |
}; | |
public static DatabaseQueryResult<T> Empty() => new() | |
{ | |
Type = DatabaseQueryResultType.Empty | |
}; | |
public static DatabaseQueryResult<T> ClientError(string description) => new() | |
{ | |
Type = DatabaseQueryResultType.ClientError, | |
ErrorDescription = description | |
}; | |
public static DatabaseQueryResult<T> ServerError(string description) => new() | |
{ | |
Type = DatabaseQueryResultType.ServerError, | |
ErrorDescription = description | |
}; | |
} | |
public DatabaseQueryResult<IEnumerable<Item>> GetAllItemsFromDatabase(...) | |
{ | |
try | |
{ | |
var result = ContactDatabaseSomehow(...); | |
if (result is IEnumerable<Item> items) | |
{ | |
return DatabaseQueryResult<IEnumerable<Item>>.Found(items); | |
} | |
} | |
catch (/*exception indicating client error*/) | |
{ | |
return DatabaseQueryResult<IEnumerable<Item>>.ClientError(exception.Message); | |
} | |
catch (/*exception indicating server error*/) | |
{ | |
return DatabaseQueryResult<IEnumerable<Item>>.ServerError(exception.Message); | |
} | |
return DatabaseQueryResult<IEnumerable<Item>>.Empty(); | |
} | |
public void ShowItems() | |
{ | |
var result = GetAllItemsFromDatabase(...); | |
if (result.IsFound(out var items)) | |
{ | |
foreach (var item in items) | |
{ | |
Console.WriteLine(item.ToString()); | |
} | |
} | |
else if (result.IsError(out var description)) | |
{ | |
Console.WriteLine($"Error! {description}"); | |
} | |
else | |
{ | |
Console.WriteLine("No items found!"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public record Found<T>(T Value); | |
public record Empty(); | |
public record ClientError(string Description); | |
public record ServerError(string Description); | |
public sealed class DatabaseQueryResult<T> | |
{ | |
private object _value; | |
private DatabaseQueryResult<T>(object value) => | |
_value = value; | |
public bool IsSuccess([NotNullWhen(true)] out T? value) | |
{ | |
if (_value is Found<T> found) | |
{ | |
value = found.Value; | |
return true; | |
} | |
_value = default; | |
return false; | |
} | |
public bool IsError([NotNullWhen(true)] out string? description) | |
{ | |
description = null; | |
if (_value is ClientError clientError) | |
{ | |
description = clientError.Description; | |
} | |
if (_value is ServerError serverError) | |
{ | |
description = serverError.Description; | |
} | |
return description is null; | |
} | |
public bool IsEmpty() => | |
_value is Empty; | |
public U Map<U>( | |
Func<T, U> found, | |
Func<U> empty, | |
Func<string, U> error | |
) | |
{ | |
if (_value is Found<T> foundValue) | |
{ | |
return found(foundValue.Value); | |
} | |
else if (_value is ClientError clientErrorValue) | |
{ | |
return error(clientErrorValue.Description); | |
} | |
else if (_value is ServerError serverErrorValue) | |
{ | |
return error(serverErrorValue.Description); | |
} | |
return empty(); | |
} | |
public U Map<U>( | |
Func<T, U> found, | |
Func<U> empty, | |
Func<string, U> clientError, | |
Func<string, U> serverError | |
) | |
{ | |
if (_value is Found<T> foundValue) | |
{ | |
return found(foundValue.Value); | |
} | |
else if (_value is ClientError clientErrorValue) | |
{ | |
return clientError(clientErrorValue.Description); | |
} | |
else if (_value is ServerError serverErrorValue) | |
{ | |
return serverError(serverErrorValue.Description); | |
} | |
return empty(); | |
} | |
public void Match( | |
Action<T> found, | |
Action empty, | |
Action<string> error | |
) | |
{ | |
if (_value is Found<T> foundValue) | |
{ | |
found(foundValue.Value); | |
} | |
else if (_value is ClientError clientErrorValue) | |
{ | |
error(clientErrorValue.Description); | |
} | |
else if (_value is ServerError serverErrorValue) | |
{ | |
error(serverErrorValue.Description); | |
} | |
empty(); | |
} | |
public Match( | |
Action<T> found, | |
Action empty, | |
Action<string> clientError, | |
Action<string> serverError | |
) | |
{ | |
if (_value is Found<T> foundValue) | |
{ | |
found(foundValue.Value); | |
} | |
else if (_value is ClientError clientErrorValue) | |
{ | |
clientError(clientErrorValue.Description); | |
} | |
else if (_value is ServerError serverErrorValue) | |
{ | |
serverError(serverErrorValue.Description); | |
} | |
empty(); | |
} | |
public static implicit operator DatabaseQueryResult<T>(Found<T> found) => new(); | |
public static implicit operator DatabaseQueryResult<T>(Empty empty) => new(); | |
public static implicit operator DatabaseQueryResult<T>(ClientError clientError) => new(); | |
public static implicit operator DatabaseQueryResult<T>(ServerError serverError) => new(); | |
} | |
public DatabaseQueryResult<IEnumerable<Item>> GetAllItemsFromDatabase(...) | |
{ | |
try | |
{ | |
var result = ContactDatabaseSomehow(...); | |
if (result is IEnumerable<Item> items) | |
{ | |
return new Found<IEnumerable<Item>>(items); | |
} | |
} | |
catch (/*exception indicating client error*/) | |
{ | |
return new ClientError(exception.Message); | |
} | |
catch (/*exception indicating server error*/) | |
{ | |
return new ServerError(exception.Message); | |
} | |
return new Empty(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment