Apariencia
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étodo | Retorno | Restricción |
|---|---|---|
FindReason<T>() | T? | T : class, INode |
HasReason<T>() | bool | T : class, INode |
TryGetReason<T>(out T? reason) | bool | T : 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.