Skip to content

Producir y consumir errores ​

La composición de un error es independiente de cómo lo devuelve un método. Puedes devolver un error directamente o incluirlo en un Result<T>, junto con el estado de la operación. Crear y devolver un error no lanza una excepción.

Los ejemplos de cada sección se complementan: coloca sus bloques en el mismo archivo C#, con los using al principio y las llamadas antes de las funciones locales.

Sin Result ​

Producir un error ​

Este método valida una cantidad y devuelve Error?. Por contrato de este ejemplo, null significa que no hay error. Esta convención la define el método; no es un resultado de éxito de Greencore.

csharp
using System;
using Greencore.Platform.Errors;
using Greencore.Platform.Errors.Trees;
using Greencore.Platform.Errors.Extensions;

static Error? ValidarCantidad(int cantidad)
{
    if (cantidad > 0)
        return null;

    return Error.Create("La cantidad no es válida.")
        .WithMetadata("Code", "INVALID_QUANTITY")
        .WithReason("La cantidad debe ser mayor que cero.");
}

Consumir el error ​

El consumidor comprueba si recibió un error. Puede pasarlo a otro método, leer sus datos o mostrar el árbol:

csharp
static void ProcesarCantidad(int cantidad)
{
    var error = ValidarCantidad(cantidad);

    if (error is not null)
    {
        MostrarError(error);
        return;
    }

    Console.WriteLine($"Cantidad: {cantidad}");
}

static void MostrarError(Error error)
{
    Console.WriteLine(error.ToString(new TreeFormatOptions
    {
        IncludeMetadata = true
    }));
}

Prueba las dos ramas colocando estas llamadas antes de las funciones:

csharp
ProcesarCantidad(0);  // Muestra el error con su causa y su código.
ProcesarCantidad(12); // Muestra: Cantidad: 12

Este contrato es útil cuando solo necesitas informar de errores de validación y el consumidor ya dispone del valor original.

Con Result ​

Producir un resultado con error ​

Result<T> expresa éxito con un valor o fallo con un error. Aquí, el método convierte un texto en una cantidad positiva: devuelve Result<int>.Ok(cantidad) o Result<int>.Fail(error).

csharp
using System;
using Greencore.Platform.Errors;
using Greencore.Platform.Errors.Trees;
using Greencore.Platform.Errors.Extensions;
using Greencore.Platform.Results;

static Result<int> LeerCantidad(string texto)
{
    if (!int.TryParse(texto, out var cantidad))
    {
        var error = Error.Create("No se pudo leer la cantidad.")
            .WithMetadata("Code", "INVALID_QUANTITY")
            .WithReason("El valor debe ser un número entero válido.");

        return Result<int>.Fail(error);
    }

    if (cantidad <= 0)
    {
        var error = Error.Create("No se pudo leer la cantidad.")
            .WithMetadata("Code", "INVALID_QUANTITY")
            .WithReason("La cantidad debe ser mayor que cero.");

        return Result<int>.Fail(error);
    }

    return Result<int>.Ok(cantidad);
}

Consumir el resultado y su error ​

TryGetValue(...) permite separar las dos ramas. Cuando devuelve false, el resultado contiene un error que puedes consumir como cualquier Error:

csharp
static void MostrarCantidad(string texto)
{
    var resultado = LeerCantidad(texto);

    if (resultado.TryGetValue(out var cantidad))
    {
        Console.WriteLine($"Cantidad: {cantidad}");
        return;
    }

    Console.WriteLine(resultado.Error.ToString(new TreeFormatOptions
    {
        IncludeMetadata = true
    }));
}

Coloca estas llamadas antes de las funciones:

csharp
MostrarCantidad("abc"); // Fallo de conversión.
MostrarCantidad("0");   // Fallo de validación.
MostrarCantidad("12");  // Éxito con valor 12.

También puedes comprobar IsError o IsOk. Accede a Error solo en un fallo y a Value solo en un éxito: acceder a la propiedad equivocada lanza InvalidOperationException.

Para operaciones sin valor de retorno, utiliza VoidResult.Ok() y VoidResult.Fail(error).

Leer los datos del error ​

Este consumidor sirve tanto para el error devuelto directamente como para resultado.Error después de comprobar el fallo:

csharp
static void MostrarDetalle(Error error)
{
    Console.WriteLine(error.Message);

    if (error.Metadata.Values.TryGetValue("Code", out var codigo))
        Console.WriteLine($"Código: {codigo}");

    foreach (var causa in error.Reasons)
        Console.WriteLine(causa.Message);
}

Reasons contiene las causas inmediatas. Para acceder a todos los niveles, las hojas o las rutas, continúa con recorrer y consultar errores. Para encadenar operaciones, consulta resultados y composición.

Las búsquedas se realizan sobre el error: consulta buscar errores y razones y la migración desde Result.

Uso personal limitado. Uso comercial sujeto a autorización escrita.