Skip to content

IFinResponse Wrapper Limitations

A wrapper interface can reduce reflection from 3 places to 1. So can the remaining 1 place also be eliminated? This section analyzes where the wrapper approach is valid and where it hits its limits.

After completing this section, you will be able to:

  1. Explain the principle by which a wrapper interface reduces reflection from 3 to 1 place
  2. Understand why CreateFail remains unsolvable with the wrapper approach
  3. Explain the design complexity of the dual interface problem (business + wrapper)
  4. Derive the requirements (Section 4) needed for a complete solution

1. Reducing Reflection with a Wrapper Interface

Section titled “1. Reducing Reflection with a Wrapper Interface”

Define a wrapper interface that exposes Fin<T>’s state:

public interface IFinResponseWrapper
{
bool IsSucc { get; }
bool IsFail { get; }
Error GetError();
}

This allows the Pipeline to access it via is IFinResponseWrapper casting:

if (response is IFinResponseWrapper wrapper)
{
if (wrapper.IsSucc)
LogSuccess();
else
LogError(wrapper.GetError());
}

Reflection disappears from IsSucc property lookup and Error extraction, leaving only 1 is casting site.

The core limitation of the wrapper approach is failure response creation. When a Pipeline needs to create a failure response on Validation failure:

// The Pipeline must return TResponse
// But it doesn't know TResponse's concrete type, so it can't create one
public static TResponse CreateFail<TResponse>(Error error) => ???

Since IFinResponseWrapper has no factory method, failure response creation still requires reflection or another workaround.

The wrapper approach requires two interfaces:

InterfaceRoleUsed in
IResponseBusiness response markerHandler, Usecase
IFinResponseWrapperExposing Fin statePipeline

The response type must implement both interfaces, which increases design complexity:

public record ResponseWrapper<T>(T? Value, Error? Error)
: IResponse, IFinResponseWrapper // Two interfaces required
where T : IResponse

Placing the two approaches side by side makes clear what the wrapper solved and what problems remain.

ItemDirect Usage (Section 2)Wrapper Usage (Section 3)
IsSucc accessReflectionis casting
Error extractionReflectionInterface member
CreateFailReflectionStill not possible
Reflection count3 places1 place

Q1: Why is is casting better than reflection in the wrapper approach?

Section titled “Q1: Why is is casting better than reflection in the wrapper approach?”

A: is casting is an operation performed directly by the CLR’s type system, and is tens of times faster than reflection (GetType().GetProperty()). Additionally, IFinResponseWrapper interface members are verified at compile time, preventing mistakes like property name typos.

Q2: Can’t we solve this by adding CreateFail to the wrapper?

Section titled “Q2: Can’t we solve this by adding CreateFail to the wrapper?”

A: CreateFail is a static factory method, so it cannot be added to an instance interface. While an instance CreateFail method could be added to IFinResponseWrapper, in cases where a failure response must be created when no response instance exists yet (Validation failure), there is no instance to call the method on. This is why static abstract and CRTP are needed.

Q3: What exactly is the dual interface problem?

Section titled “Q3: What exactly is the dual interface problem?”

A: In the wrapper approach, the response type must separately implement a business marker (IResponse) and Fin state exposure (IFinResponseWrapper). This increases design complexity and creates the problem that types not implementing both interfaces cannot pass through Pipelines. Part 3’s FinResponse<A> unifies this into a single type.

03-IFinResponse-Wrapper-Limitation/
├── FinResponseWrapperLimitation/
│ ├── FinResponseWrapperLimitation.csproj
│ ├── IFinResponseWrapper.cs
│ └── Program.cs
├── FinResponseWrapperLimitation.Tests.Unit/
│ ├── FinResponseWrapperLimitation.Tests.Unit.csproj
│ ├── xunit.runner.json
│ └── FinResponseWrapperTests.cs
└── README.md
Terminal window
# Run the program
dotnet run --project FinResponseWrapperLimitation
# Run tests
dotnet test --project FinResponseWrapperLimitation.Tests.Unit

Consolidating all attempts so far, the next section organizes the 4 requirements the response type system must fulfill and the capability matrix per Pipeline.

Section 2.4: Requirements Summary