Избегайте нулевой проверки с помощью лямбды
В этой статье следует избегать нулевых проверок, заменив искатели счетчиками. Автор приводит пример Ruby, чтобы избежать проверки на ноль: если объект возвращается, блок запускается, если нет, то это не так.
data_source.person(id) do |person|
person.phone_number = phone_number
data_source.update_person person
end
Я хотел бы сделать то же самое в C# с использованием лямбда-функции, но у меня возникли проблемы при создании примера, который делает то же самое. Не могли бы вы создать фабрику объектов, которая бы принимала номер идентификатора и лямбда-функцию?
2 ответа
Ну, я не знаю Ruby и не понимаю точный приведенный пример, но я подозреваю, что это будет что-то вроде:
dataSource.Update(id, person => person.PhoneNumber = phoneNumber);
куда DataSource.Update
было бы:
- Иметь подпись что-то вроде
void Update(string id, Action<Person> updateAction
(или, возможно, вернутьbool
указать, нашел ли он человека) - Быть реализованным как:
- Найти человека с данным ID
- Если он не существует, немедленно вернитесь
- В противном случае выполните данное действие и обновите хранилище резервных копий с измененным объектом.
Или в более общем смысле (и ближе к оригинальному Ruby):
dataSource.WithPerson(id, person => {
person.PhoneNumber = phoneNumber;
dataSource.UpdatePerson(person);
};
Лично я предпочитаю первую форму: она более конкретна в отношении того, чего она пытается достичь, но она вполне может подойти к лучшей реализации, и она, безусловно, чище в вызывающем коде.
Альтернативным подходом было бы использование монады Maybe.
Это позволит вам сохранить существующий API как есть, то есть вы все еще можете иметь dataSource.GetPersonById(id)
,
Код, который использует монаду Maybe, выглядит следующим образом:
dataSource.GetPersonById(id)
.Maybe()
.Do(person => {
person.PhoneNumber = phoneNumber;
dataSource.UpdatePerson(person);
});
Чтобы иметь возможность использовать монаду Maybe, вам потребуется код в следующем абзаце.
Основой для этого послужил код из ссылки в блоге Дэниела Эрвикера.
Я расширил его, чтобы добавить Maybe
метод расширения и сделал его компиляцией.
public struct MaybeMonad<T> where T : class
{
private readonly T _value;
public MaybeMonad(T value)
{
_value = value;
}
public MaybeMonad<TResult> Select<TResult>(Func<T, TResult> getter)
where TResult : class
{
var result = (_value == null) ? null : getter(_value);
return new MaybeMonad<TResult>(result);
}
public TResult Select<TResult>(Func<T, TResult> getter,
TResult alternative)
{
return (_value == null) ? alternative : getter(_value);
}
public void Do(Action<T> action)
{
if (_value != null)
action(_value);
}
}
public static class Maybe
{
public static MaybeMonad<T> From<T>(T value) where T : class
{
return new MaybeMonad<T>(value);
}
}
public static class MaybeMonadExtensions
{
public static MaybeMonad<T> Maybe<T>(this T value) where T : class
{
return new MaybeMonad<T>(value);
}
}