C#
L-użu tar-Result Pattern f’C# Minflok ma Tirritorna Null
Ir-Result Pattern jagħmel l-istati mistennija ta’ suċċess u falliment espliċiti, u jipprovdi alternattiva aktar ċara milli tirritorna null jew tarmi exceptions għal riżultati tan-negozju ta’ rutina.
Tgħallimt ir-Result Pattern waqt li kont qed naħdem b’.NET, u dan biddel il-mod kif naħseb dwar methods li jistgħu jfallu. Minflok jirritorna null u jħalli lil min isejjaħlu jinterpreta xi jfisser, il-method jirritorna object li jiddeskrivi jew suċċess jew falliment.
Dan ma jfissirx li kull nullable value jew exception għandha tisparixxi. Il-pattern huwa l-aktar utli meta l-falliment ikun riżultat mistenni u min isejjaħ ikollu bżonn jifhem x’ġara.
Il-limitazzjoni meta tirritorna null
Ikkunsidra repository method li jirritorna null meta ma jkunx jista’ jsib user. Min isejjaħ jista’ jiċċekkja għal null, iżda l-value ma jispjegax ir-raġuni. Kien l-identifier invalidu? Il-user kien nieqes? Falliet xi validation oħra?
Nullable reference types itejbu din is-sitwazzjoni billi jippermettulna nesprimu jekk reference hijiex maħsuba biex taċċetta null. Il-compiler ta’ C# imbagħad juża static analysis biex iwissi dwar null assignments u dereferences possibbli. Madankollu, din hija compile-time feature; ma toħloqx runtime type separat u lanqas iżżid runtime validation. (learn.microsoft.com)
Result<T> jagħti tifsira lir-riżultat tal-operazzjoni. Minflok jirritorna User?, method jista’ jirritorna Result<User> li jkun fih jew il-user jew error speċifiku.
Ir-rappreżentazzjoni tal-errors
L-ewwel parti hija error type żgħir:
public record Error(string Code, string Message)
{
public static Error None = new(string.Empty, string.Empty);
public static Error NullValue = new("Error.NullValue", "Um valor nulo foi fornecido.");
}
Il-code jipprovdi identifier stabbli għal deċiżjonijiet programmatic u message li jista’ jiġi logged jew muri. Error.None jirrappreżenta operazzjoni li rnexxiet, fejn ma jeżisti ebda error.
Il-ħolqien tar-Result type
Ir-Result mhux generic jirrappreżenta operazzjonijiet li jirnexxu mingħajr ma jirritornaw value:
public class Result
{
protected Result(bool isSuccess, Error error)
{
switch (isSuccess)
{
case true when error != Error.None:
throw new InvalidOperationException();
case false when error == Error.None:
throw new InvalidOperationException();
default:
IsSuccess = isSuccess;
Error = error;
break;
}
}
public bool IsSuccess { get; }
public bool IsFailure => !IsSuccess;
public Error Error { get; }
public static Result Success() => new(true, Error.None);
public static Result Failure(Error error) => new(false, error);
public static Result<T> Success<T>(T value) => new(value, true, Error.None);
public static Result<T> Failure<T>(Error error) => new(default, false, error);
public static Result<T> Create<T>(T? value) =>
value is not null ? Success(value) : Failure<T>(Error.NullValue);
}
Il-constructor jipproteġi żewġ regoli importanti: result ta’ suċċess ma jistax ikun fih error, u result li falla jrid ikun fih wieħed. Meta dawn l-istati jinżammu validi, jiġu evitati objects kontradittorji bħal result ta’ suċċess b’error message.
Għal operazzjonijiet li jirritornaw data, il-verżjoni generic taħżen il-value ta’ suċċess:
public class Result<T> : Result
{
private readonly T? _value;
protected internal Result(T? value, bool isSuccess, Error error) : base(isSuccess, error)
=> _value = value;
[NotNull]
public T Value => _value! ?? throw new InvalidOperationException("Result has no value");
public static implicit operator Result<T>(T? value) => Create(value);
}
Il-property Value hija disponibbli għal results ta’ suċċess. Jekk tiġi aċċessata wara falliment, tintefa’ InvalidOperationException, għalhekk il-konsumaturi għandhom l-ewwel jispezzjonaw l-istat tar-result. Il-pattern jagħmel il-contract aktar ċar, iżda xorta jiddependi fuq użu korrett fil-call site.
Tirritorna user mingħajr ma tirritorna null
Lookup method issa jista’ jikkomunika b’mod espliċitu fallimenti mistennija differenti:
public Result<User> GetUserById(int userId)
{
if (userId <= 0)
return Result.Failure<User>(Error.InvalidUserId);
var user = _userRepository.FindById(userId);
if (user == null)
return Result.Failure<User>(Error.UserNotFound);
return Result.Success(user);
}
Jekk nassumu li InvalidUserId u UserNotFound huma definiti fl-error catalog, ir-return type jgħid lill-konsumaturi li l-method għandu żewġ stati possibbli. Min isejjaħ jista’ jittrattahom direttament:
var result = GetUserById(123);
if (result.IsSuccess)
{
Console.WriteLine($"User found: {result.Value.Name}");
}
else
{
Console.WriteLine($"Failed to retrieve user: {result.Error.Message}");
}
Dan huwa aktar deskrittiv milli tiċċekkja jekk User ritornat huwiex null. Iżomm ukoll ir-riżultati tan-negozju mistennija viżibbli fil-control flow normali.
Result ma jiħux post l-exceptions
L-exceptions jibqgħu xierqa għal kundizzjonijiet mhux mistennija li ma jistgħux jiġu ttrattati bħala parti mill-operazzjoni normali. Il-gwida ta’ .NET tirrakkomanda li jiġu evitati exceptions għal kundizzjonijiet ta’ rutina, filwaqt li jintuża exception handling għal avvenimenti ġenwinament eċċezzjonali. (learn.microsoft.com)
Distinzjoni prattika hija:
- Irritorna result għal validation failures, records neqsin, kunflitti u riżultati mistennija oħra.
- Itfa’ exceptions għal programming errors, stat invalidu ta’ object, jew infrastructure failures mhux mistennija li l-layer attwali ma jistax jittratta b’mod sinifikanti.
Ir-Result Pattern mhuwiex primarjament dwar li telimina null jew exceptions minn kullimkien. Huwa dwar li tagħti type espliċitu lill-fallimenti mistennija u tagħmel il-method contracts aktar faċli biex jinftiehmu.
Żewġ trattamenti prattiċi addizzjonali tal-pattern huma disponibbli fuq https://www.red-gate.com/simple-talk/development/dotnet-development/the-result-pattern-in-asp-net-core-minimal-apis/ u https://medium.com/@emrecantopaloglu/the-result-pattern-in-net-a-simple-guide-73a8f1b89d73.
Referenzi
- Nullable reference types - C# reference | Microsoft Learn — learn.microsoft.com
- Best practices for exceptions - .NET | Microsoft Learn — learn.microsoft.com
- The Result Pattern In Asp Net Core Minimal Apis — red-gate.com
- The Result Pattern In Net A Simple Guide 73A8f1b89d73 — medium.com