Skip to content

refactor: Replace all throw statements with return-error pattern — add structured error types #8

@mephist-cne

Description

@mephist-cne

Summary

Replace all throw statements throughout CSLibrary2026 with a return-error pattern. Introduce structured error/result types so callers can handle failures gracefully without risking unhandled exceptions or application crashes.

Background

Throwing exceptions at runtime is dangerous in library code consumed by apps:

  • Unhandled exceptions crash the application
  • Callers have no compile-time safety net for handling specific failure modes
  • Exceptions cannot be awaited cleanly in async contexts without try/catch wrappers everywhere
  • Library should communicate failure as a return value, not an exception

Requirement

1. Audit All throw Statements

Search the entire codebase for throw statements in production (non-test) code:

grep -rn "throw new" Source/ --include="*.cs" | grep -v "throw new NotImplementedException\|throw new ExecutionEngineException\|#if DEBUG\|#if NETCFDESIGNTIME\|Test\|Mock"

Categorize each throw into:

  • Replaceable — should return an error instead
  • Acceptablethrow new NotImplementedException() for stubs is fine
  • Criticalthrow for truly unrecoverable/programming errors (e.g., InvalidOperationException on misuse of internal state)

2. Define Structured Error Types

Create a result/error enum or class in a shared location (e.g., CSLibrary.Results or CSLibrary.ErrorCodes):

namespace CSLibrary
{
    /// <summary>
    /// Result codes returned by CSLibrary operations.
    /// </summary>
    public enum Result
    {
        OK = 0,
        NOT_INITIALIZED = 1,
        NOT_SUPPORTED = 2,
        DEVICE_NOT_CONNECTED = 3,
        TRANSPORT_ERROR = 4,
        TIMEOUT = 5,
        INVALID_PARAMETER = 6,
        ALREADY_INITIALIZED = 7,
        PERMISSION_DENIED = 8,
        INTERNAL_ERROR = 99,
    }
}

3. Replace throw with Return-Error Pattern

For each replaceable throw, change the method signature to return Result (or a more specific enum) and return the appropriate error code:

// Instead of:
public void Connect(string address)
{
    if (string.IsNullOrEmpty(address))
        throw new ArgumentNullException(nameof(address));
    // ...
}

// Do:
public Result Connect(string address)
{
    if (string.IsNullOrEmpty(address))
        return Result.INVALID_PARAMETER;
    // ...
    return Result.OK;
}

4. Preserved throw Cases

The following throw patterns are acceptable and should NOT be changed:

  • throw new NotImplementedException() — for stub methods not yet implemented
  • throw new InvalidOperationException(...) in constructor/init — for truly unrecoverable misconfiguration
  • throw inside #if DEBUG blocks
  • throw inside unit test files

Scope

Files to audit (all .cs under Source/):

  • Source/HAL/ — all HAL implementations (TCP, BLE, etc.)
  • Source/RFIDReader/ — all RFID reader API classes
  • Source/Transport/ — transport layer
  • Source/Notification/ — notification handling
  • Source/BarcodeReader/ — barcode reader HAL
  • Source/Properties/ — assembly attributes (no changes expected)

Files Expected to Change

  • Source/HAL/TCPIP/NetFinder.cs — may have throw statements
  • Source/HAL/TCPIP/ClassDeviceFinder.cs — may have throw statements
  • Source/HAL/Plugin.BLE/DeviceFinder.cs — may have throw statements
  • Various Source/RFIDReader/ files — may have throw for invalid parameters or transport errors

Acceptance Criteria

  • Audit complete — all throw statements categorized
  • Result (or similar) enum created in appropriate namespace
  • All replaceable throw statements converted to return Result error codes
  • dotnet build -c Release succeeds with 0 errors
  • No throw new Exception or throw new ArgumentNullException in production HAL/RFIDReader code

Notes

  • #if ANDROID, #if DEBUG, #if BIGENDIAN guards are acceptable and should not be modified
  • All content must be English
  • Keep the changes focused: only replace throw with return-error, do not refactor other logic at the same time

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions