Skip to content

Referenciar una causa como error ​

ReferenceError permite entregar una causa existente a un consumidor que necesita un Error. Conserva la misma instancia y su padre original: el diagnóstico se puede consultar desde dos entradas sin duplicarlo.

Caso de uso: respuesta por fila y diagnóstico del lote ​

Una importación valida filas de un archivo. Necesita conservar todas las causas en un diagnóstico del lote y entregar a cada consumidor únicamente el fallo de su fila. El contrato del consumidor recibe Error, mientras que cada fila está representada por un Reason que ya pertenece al lote.

Aquí hace falta una referencia por tres razones:

  • Un Reason no es un Error, por lo que no puede devolverse directamente con ese contrato.
  • Devolver el error del lote incluiría los fallos de otras filas.
  • Agregar la misma causa a otro Error intentaría darle un segundo padre y lanzaría InvalidOperationException.

ReferenceError.Create(fila) crea una raíz que referencia esa causa. La fila conserva su pertenencia al lote, y la respuesta individual conserva su identidad, metadatos y causas.

Producir y consumir la respuesta individual ​

Este ejemplo completo utiliza null para indicar una fila válida. La misma idea puede aplicarse a Result, como se muestra más adelante.

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

var lote = Error.Create("El lote contiene filas inválidas.")
    .WithMetadata("File", "customers.csv");

var errorFila7 = ValidarFila(lote, 7, "");
var errorFila12 = ValidarFila(lote, 12, "");
var errorFila15 = ValidarFila(lote, 15, "Ana");

MostrarResultadoFila(7, errorFila7);
MostrarResultadoFila(12, errorFila12);
MostrarResultadoFila(15, errorFila15);

Console.WriteLine("Diagnóstico completo del lote:");
Console.WriteLine(lote.ToString(new TreeFormatOptions { IncludeMetadata = true }));

static Error? ValidarFila(Error lote, int numero, string nombre)
{
    if (!string.IsNullOrWhiteSpace(nombre))
        return null;

    var fila = lote.AddReason($"La fila {numero} contiene datos inválidos.")
        .WithMetadata("Row", numero)
        .WithReason("El nombre es obligatorio.");

    return ReferenceError.Create(fila);
}

static void MostrarResultadoFila(int numero, Error? error)
{
    if (error is null)
    {
        Console.WriteLine($"Fila {numero}: válida.");
        return;
    }

    Console.WriteLine($"Respuesta individual de la fila {numero}:");
    Console.WriteLine(error.ToString(new TreeFormatOptions { IncludeMetadata = true }));
}

La respuesta de la fila 7 contiene únicamente su diagnóstico:

text
Respuesta individual de la fila 7:
ReferenceError
└── La fila 7 contiene datos inválidos. [Row=7]
    └── El nombre es obligatorio.

El lote conserva ambas filas inválidas:

text
Diagnóstico completo del lote:
El lote contiene filas inválidas. [File=customers.csv]
├── La fila 7 contiene datos inválidos. [Row=7]
│   └── El nombre es obligatorio.
└── La fila 12 contiene datos inválidos. [Row=12]
    └── El nombre es obligatorio.

La fila 15 no agrega causas y su respuesta es Fila 15: válida.. En una importación real, el lote se considera fallido si se agregaron causas; crear el contenedor no determina por sí solo el estado de la operación.

ReferenceError es el mensaje predeterminado de la raíz envolvente. El mensaje de la fila está en su causa referenciada. Los metadatos del lote, como File, no se copian a la referencia ni se heredan por la fila.

Comprobar identidad y pertenencia ​

Añade estas comprobaciones después de validar las filas y antes de las funciones locales:

csharp
var fila7 = lote.Reasons[0];

Console.WriteLine(ReferenceEquals(errorFila7!.Reasons[0], fila7)); // True
Console.WriteLine(ReferenceEquals(fila7.Parent, lote));           // True
Console.WriteLine(errorFila7.OwnedReasons.Count);                 // 0

Reasons permite recorrer la causa referenciada. OwnedReasons está vacío porque la referencia no adopta esa causa. Parent sigue apuntando al lote.

Devolver la referencia con Result ​

Si el consumidor necesita un resultado con estado, puedes adaptar el método anterior a una operación sin valor de retorno. Agrega using Greencore.Platform.Results; al principio del archivo:

csharp
static VoidResult ValidarFilaConResultado(Error lote, int numero, string nombre)
{
    var error = ValidarFila(lote, numero, nombre);
    return error is null ? VoidResult.Ok() : VoidResult.Fail(error);
}

El consumidor obtiene únicamente el error de su fila:

csharp
var otroLote = Error.Create("El lote contiene filas inválidas.");
var resultado = ValidarFilaConResultado(otroLote, 7, "");

if (resultado.IsError)
    Console.WriteLine(resultado.Error.ToString());

Dentro de un productor que ya dispone del Reason, la operación esencial es VoidResult.Fail(ReferenceError.Create(fila)). Pasar directamente fila a Fail(...) no compila: requiere un Error.

Referencia viva y recorridos ​

La referencia conserva objetos vivos. Si agregas causas o modificas metadatos en la fila original, esos cambios se observan desde el lote y desde su referencia. No es una copia del diagnóstico en el momento de crear la respuesta.

TreeTraversal y TreeQuery siguen Reasons, de modo que también recorren las causas referenciadas. En cambio, fila.Root() sigue Parent y devuelve el lote original, no la raíz envolvente. Si recorres un diagnóstico que contiene tanto el lote como la referencia a una de sus filas, esa fila aparecerá por ambos caminos.

Consulta recorrer y consultar errores para enumerar nodos, hojas y rutas.

Contrato de la fábrica ​

csharp
public static Error Create(INode reason)
ArgumentoResultado
Una causaUn nuevo ReferenceError que referencia esa instancia
Un error raízLa misma instancia recibida, sin crear otra envoltura
nullLanza ArgumentNullException

Por eso el tipo de retorno es Error y no ReferenceError:

csharp
Console.WriteLine(ReferenceEquals(ReferenceError.Create(lote), lote)); // True

Si solo necesitas mostrar una causa, puedes usar su ToString() directamente. La referencia resulta necesaria en este caso porque hay que conservar el nodo existente y entregarlo mediante un contrato que exige un error raíz.

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