Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions