didismusings.com

Proposal for a New Result Type to Address Partial Failures in C#

Written on

Understanding the Need for a New Result Type

Previously, I shared my preferred implementation of a Result type in C#, which proved adequate for 95% of my requirements. However, I've recently encountered a scenario that necessitated a different approach.

If you haven’t yet read my earlier article on the initial Result type, I highly encourage you to do so, as this discussion frequently references it. You can view it here: Drawbacks of the Original Result Type.

In a recent project, I faced a situation where I needed to process multiple items simultaneously. While everything functioned smoothly 99% of the time, there were certain items—about 1%—that inherently failed due to specific properties.

It's essential for the task to conclude successfully despite these occasional failures. However, I wanted users to be notified of these minor exceptions so they could respond appropriately. The original Result type fell short in this regard, as returning a successful result would leave the caller unaware of potential issues, while a failed result could mislead them into thinking the entire operation was unsuccessful.

Architectural Considerations

I needed a way to inform users about mild errors without halting the function’s execution prematurely, as the impact of these errors was minimal. Several strategies could be employed to achieve this:

  1. Injecting a UserInformation Service: This would involve notifying users directly within the executing service where the errors occur.
  2. Returning a Result-Exception Tuple: This approach would convey mild exceptions when they arise.
  3. Creating a PartialResultType: This type would offer three distinct states: Success, Partial Success, and Error.

The first option would violate the single responsibility principle by incorporating user notification functionality into a method primarily designed for processing items. The second option, while functional, could still lead to confusion, as the caller would need to handle potential null values when no exception occurred. Therefore, I opted for the third solution: a Partial Result Type.

Introducing the Partial Result Type

Utilizing the foundational code from my previous Result type, I adapted it to accommodate partial results. For this purpose, I implemented an Enum labeled Success, which represents the values Success, PartialSuccess, and Error.

The term PartialSuccess aptly indicates that the underlying method executed successfully overall, but not completely. Unlike PartialFailure, which implies a complete failure, PartialSuccess allows for more nuanced handling by the caller.

Here’s my implementation for you to utilize:

public enum Success

{

Success,

PartialSuccess,

Error

}

public class PartialResult

{

protected readonly Exception? error;

public Success Success { get; protected set; }

public bool Succeeded => Success == Success.Success || Success == Success.PartialSuccess;

public bool SucceededPartially => Success == Success.PartialSuccess;

public string Message => error?.Message ?? "";

protected PartialResult(Success success, Exception? error)

{

Success = success;

this.error = error;

}

public Exception GetError() => error

?? throw new InvalidOperationException($"Error property for this Result not set.");

public static PartialResult Ok => new PartialResult(Success.Success, null);

public static PartialResult PartialOk(Exception error)

{

return new PartialResult(Success.PartialSuccess, error);

}

public static PartialResult Error(Exception error)

{

return new PartialResult(Success.Error, error);

}

public static implicit operator PartialResult(Exception exception) =>

new PartialResult(Success.Error, exception);

}

public sealed class PartialResult<TPayload> : PartialResult

where TPayload : class

{

private readonly TPayload? payload;

private PartialResult(TPayload? payload, Exception? error, Success success) : base(success, error)

{

this.payload = payload;

}

public PartialResult(TPayload payload) : base(Success.Success, null)

{

this.payload = payload ?? throw new ArgumentNullException(nameof(payload));

}

public PartialResult(TPayload payload, Exception error) : base(Success.PartialSuccess, error)

{

this.payload = payload ?? throw new ArgumentNullException(nameof(payload));

}

public PartialResult(Exception error) : base(Success.Error, error)

{

}

public TPayload GetOk() => Success == Success.Success || Success == Success.PartialSuccess

? payload ?? throw new InvalidOperationException($"Payload for Result<{typeof(TPayload)}> was not set.") : throw new InvalidOperationException($"Operation for Result<{typeof(TPayload)}> was not successful.");

public new Exception GetError() => error

?? throw new InvalidOperationException($"Error property for Result<{typeof(TPayload)}> not set.");

public new static PartialResult<TPayload> Ok(TPayload payload)

{

return new PartialResult<TPayload>(payload, null, Success.Success);

}

public static PartialResult<TPayload> PartialOk(TPayload payload, Exception error)

{

return new PartialResult<TPayload>(payload, error, Success.PartialSuccess);

}

public new static PartialResult<TPayload> Error(Exception error)

{

return new PartialResult<TPayload>(null, error, Success.Error);

}

public static implicit operator PartialResult<TPayload>(TPayload payload) =>

new(payload, null, Success.Success);

public static implicit operator PartialResult<TPayload>(Exception exception) =>

new(exception);

}

As illustrated, we now have a PartialOk initializer that yields a successful result while still flagging an exception for the caller to check.

When to Implement Partial Results

While the Partial Result type is a powerful tool, it should be employed judiciously. When a caller receives a Partial Result, they must always verify if there was a partial success, which may not be necessary in many cases.

It’s advisable to implement both Result and PartialResult within your codebase and apply each where appropriate.

If you haven’t explored the original proposed Result type, I encourage you to do so! It not only outlines its functionality but also shares various useful extensions I’ve conceived while working with it.

Furthermore, if you wish to examine the source code for the PartialResult type, please visit my GitHub Repository.

Thank you for taking the time to read this piece. I hope you found it insightful and enriching. Your support and engagement mean a lot to me.

If you’re interested in staying informed about the latest trends, tips, and techniques in clean architecture, clean coding, and modern tech stacks—particularly with C#, .NET, and Angular—I would be grateful if you considered following me.

Wishing you a fantastic day! By doing so, you'll gain access to an invaluable platform that connects new writers and readers while fostering daily learning opportunities.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Boosting Productivity with PopClip: A Must-Have Mac Tool

Discover how PopClip enhances productivity on Mac with instant text actions and customizable extensions.

Unlock Your Computer's Hidden Productivity Potential Today

Discover effective strategies to enhance your computer productivity with practical tips and tools.

Healing Across Distances: A Journey of Recovery and Discovery

A tale of long-distance healing, personal growth, and the unexpected powers we may discover within ourselves.

Essential Habits for Personal Growth and Transformation

Discover five impactful habits to enhance your self-improvement journey.

Embracing Leadership and Curiosity: Lessons from My Past

Discover valuable insights on taking initiative, fostering genuine curiosity, and shifting perspectives for personal growth.

# Does

Discover how faking confidence can transform your self-image and lead to genuine self-assurance.

A Letter to My Past Self: Lessons from the Future

Reflecting on future lessons to guide the past self towards a better life.

# Exploring the Enigmatic Presence of Aliens and Our Reality

A deep dive into humanity's relationship with reality and the potential existence of extraterrestrial intelligence.