Skip to content

Buscar razones ​

Las consultas de razones se invocan sobre Error y excluyen su raíz. Recorren todos los niveles de Reasons, incluyendo nodos intermedios.

MétodoRetornoRestricción
FindReason<T>()T?T : class, INode
HasReason<T>()boolT : class, INode
TryGetReason<T>(out T? reason)boolT : class, INode

Razones dinámicas ​

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

var error = Error.Create("Importación fallida.")
    .WithReason(new Reason("Fila inválida.")
        .WithReason(new Reason("Nombre obligatorio."))
        .WithReason(new Reason("Correo inválido.")));

Console.WriteLine(error.FindReason<Reason>()?.Message.ToString()); // Fila inválida.
Console.WriteLine(error.HasReason<Reason>()); // True.

if (error.TryGetReason<Reason>(out var razon))
    Console.WriteLine(razon.Message); // Fila inválida.

La primera razón tiene hijos y aun así coincide. Si necesitas solamente hojas, usa ReasonsOfType.

Razones tipadas con datos ​

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

var error = new ImportError();
var fila = error.AddReason(new InvalidRow(7));
fila.AddReason(new MissingColumn("Email"));

if (error.TryGetReason<MissingColumn>(out var columna))
{
    Console.WriteLine(columna.ColumnName); // Email.
    Console.WriteLine(columna.Up().RowNumber); // 7.
    Console.WriteLine(ReferenceEquals(columna.Root(), error)); // True.
}

Console.WriteLine(error.HasReason<IReasonNode>()); // True.

public sealed class ImportError() : Error("Importación fallida.");

public sealed class InvalidRow(int rowNumber) : Reason<ImportError, InvalidRow>("Fila inválida.")
{
    public int RowNumber { get; } = rowNumber;
}

public sealed class MissingColumn(string columnName) : Reason<InvalidRow, MissingColumn>("Falta una columna.")
{
    public string ColumnName { get; } = columnName;
}

Reason y Reason<TParent, TSelf> son familias distintas: una razón tipada no hereda de la clase dinámica Reason. Para buscar ambas familias usa IReasonNode. Para incluir también errores referenciados usa INode.

Igualmente, error.WithReason("texto") crea un Reason<Error>; no será encontrado por FindReason<Reason>(). Puedes buscarlo con FindReason<Reason<Error>>() o FindReason<IReasonNode>().

Buscar por metadatos o propiedades ​

No hay una sobrecarga de FindReason con predicado. Combina la enumeración con LINQ:

csharp
using System;
using System.Linq;
using Greencore.Platform.Errors;
using Greencore.Platform.Errors.Extensions;
using Greencore.Platform.Nodes;

var error = Error.Create("Datos inválidos.")
    .WithReason(new Reason("Correo inválido.")
        .WithMetadata("Property", "Email"));

var correo = error.ReasonsOfType<IReasonNode>(includeNonTerminal: true)
    .FirstOrDefault(razon =>
        razon.Metadata.Values.TryGetValue("Property", out var propiedad)
        && propiedad is string nombre && nombre == "Email");

Console.WriteLine(correo?.Message.ToString()); // Correo inválido.

Lee el diccionario mediante Metadata.Values. Prefiere tipos, propiedades y códigos estables para decisiones de negocio; el mensaje puede cambiar con la localización.

Consultar solo una rama ​

Las extensiones de búsqueda reciben Error, no una razón arbitraria. Para consultar dentro de una razón, utiliza TreeTraversal.EnumerateDescendants(razon) y LINQ. Ese recorrido también excluye el nodo inicial. Consulta recorridos y navegación.

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