Przeglądając posty na blogach natrafiłem na bibliotekę, która pozwala nam walidować nasze modele/parametry w metodach/itp. Czyli pozwala nam zaimplementować guard w naszych aplikacjach 🙂 Ta biblioteka to Guard.
Co to jest guard
Jeśli nie spotkałeś się jeszcze z guard lub gardą 😀 to już tłumaczę czym jest. Jak sama nazwa wskazuje jest to strażnik. No i moim zdaniem nie ma co doszukiwać się jakiś głębszych funkcji. A więc guard sprawdza coś zanim gdzieś nas wpuści 😀 To sprawdzanie to najczęściej jakaś walidacja modelu, tego czy jesteś zalogowany, czy masz wystarczające role itp. itd. Lepszy opis znajdziesz np. tutaj
Przykłady
W poniższym przykładzie walidujemy nasz model w metodzie AddCar
.
using Dawn; public record Car { public string Model { get; set; } public string Brand { get; set; } public int Wheels { get; set; } } public record Truck : Car { public double Tonnage { get; set; } } public static void AddCar(Car car) { Guard.Argument(car.Model, nameof(car.Model)).NotNull().NotEmpty().MaxLength(50); Guard.Argument(car.Wheels, nameof(car.Model)).Equal(4); } var car = new Car { Model = "Q5", Brand = "Audi", Wheels = 4 }; AddCar(car); var truck = new Truck { Model = "Q5", Brand = "Audi", Wheels = 8 }; AddCar(truck);
Jeśli przekażemy truck
do AddCar
to dostaniemy błąd:
Error: System.ArgumentException: Model must be 4. (Parameter 'Model') at Dawn.Guard.Equal[T](ArgumentInfo`1& argument, T& other, IEqualityComparer`1 comparer, Func`3 message) at Submission#27.AddCar(Car car) at Submission#27.<>d__0.MoveNext() --- End of stack trace from previous location --- at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)
W tym przykładzie robimy to samo ale w konstruktorze. To czy to dobry czy zły pomysł to pozostawiam już Tobie. Moim zdaniem taki sobie, bo „uzależniamy” naszą klasę domenową od konkretnej biblioteki i mi to tak sobie się podoba. Ale mogę się mylić 🙂
using Dawn; public class Currency { public string Code { get; set; } public string Name { get; set; } public Currency(string code, string name) { this.Code = Guard.Argument(code, nameof(code)).NotNull().NotEmpty().Length(3); this.Name = Guard.Argument(name, nameof(name)).NotNull().NotEmpty().LengthInRange(1, 50); } } var pln = new Currency("PLN", "Złoty"); var zl = new Currency("ZL", "Złoty");
Przy tworzeniu zl
dostaniemy taki błąd:
Error: System.ArgumentException: code must consist of 3 characters. (Parameter 'code') at Dawn.Guard.Length(ArgumentInfo`1& argument, Int32 length, Func`3 message) at Submission#28.Currency..ctor(String code, String name) at Submission#28.<>d__0.MoveNext() --- End of stack trace from previous location --- at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)
Podsumowanie
Moim zdaniem Guard jest dość ciekawa ale też ostatni release był prawie 2 lata temu 🤷♂️ Ja w swoich projektach zwykle używam Fluent validation i pewnie w komercyjnych projektach zostanę przy niej. Ale jak dla mnie to brak jakiejkolwiek wstępnej konfiguracji w przypadku Guard jest super i w jakiś mniejszych aplikacjach być może jej użyję.
Repozytorium z przykładami znajdziesz tutaj.