Как мне конвертировать валидацию на строку, которая пуста при успехе? - PullRequest
1 голос
/ 22 апреля 2020

Я довольно новичок в функциональном программировании и пытаюсь работать в рамках очень императивной базы кода, поэтому я пытаюсь написать код, который в основном FP, но не может быть полностью.

I необходимо написать переопределение для следующего метода ...

protected override string CreateEntity(XElement xe)

... где xe содержит два фрагмента данных, необходимых для обновления базы данных. Метод должен проверить содержимое xe, затем выполнить обновление, возвращая "" в случае успеха или список ошибок, разделенных символом канала, если нет.

Я взял сигнал с кредитной карты проверочный пример в тестах language-ext и написал несколько вспомогательных методов, таких как следующие (реализация очень похожа на пример, поэтому опущен) ...

private Validation<string, int> ValidateRegionID(XElement xe)

В этом примере он использовал Apply на их коллекции, которая возвратила Validation, который был новым объектом кредитной карты, если все прошло нормально, или Error, если нет. В моем случае мне нечего возвращать, если все прошло хорошо (так как я делаю обновление базы данных, а не создаю новый объект), так что дошли до этого ...

Validation<string, Unit> validation = (ValidateRegionID(xe), ValidateClinAppsID(xe))
  .Apply((regionID, clinAppsID) =>
  {
    // Do the database update (yes, impure code)...
    return Unit.Default;
  });

Я не знаю, является ли это лучшим способом сделать это, поэтому любые предложения будут приветствоваться.

Моя большая проблема заключается в том, что делать дальше. Следующее работает, но выглядит не очень элегантно или FP для меня ...

return validation.IsFail
  ? string.Join("|", validation.FailAsEnumerable())
  : "";

Есть ли лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

Последняя часть вашего кода (ошибки форматирования) может быть сделана так:

        [Fact]
        void Test()
        {
            Validation<string, Unit> resultFromDatabase = Fail<string, Unit>("error");

            var showError1 = string.Join("|", resultFromDatabase.FailToSeq()); // use the fact that FailToSeq() will return empty seq for success
            var showError2 = string.Join("|", resultFromDatabase.IfSuccess(Seq<string>())); // explicitly supply a value of the error type (Seq<string>) for success case
            var showError3 = resultFromDatabase.Match(_ => "", errors => string.Join("|", errors)); // only call string.Join for errors
        }

Выберите наиболее понравившийся вам вариант. Если вы хотите иметь чистый код / ​​не полагаться на реализацию FailToSeq (), работающую в обоих случаях, вы должны явно обрабатывать оба случая, используя Match или IfSuccess / IfFail.

Если вы хотите улучшить ваш общий дизайн (избегая нечистого кода), вам, вероятно, придется изменить некоторые фундаментальные вещи. Один (очень FP) вариант - использовать Free Monad, и в LanguageExt был достигнут определенный прогресс, чтобы сделать это проще, но, вероятно, это большой шаг для преобразования традиционной базы OO-кода. См .:

https://github.com/louthy/language-ext/releases/tag/3.4.11 (бесплатная монада с использованием CodeGen) https://github.com/louthy/language-ext/wiki/Thinking-Functionally: - Архитектура приложения

0 голосов
/ 22 апреля 2020

Вы можете просто вызвать исключение в случае неудачи проверки. Тот, кто позже вызовет ваш код, может применить к нему обработку исключений.

Другой вариант - отправлять коды ошибок вместо сообщений. В этом случае вызываемый абонент может переводить код каждой ошибки в конкретную ошибку.

...