Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

В C# с типами все в порядке

Anna | 17.06.2014 | нет комментариев

Прочитав статью «Усиливаем контроль типов: где в нормальном C#-плане присутствует непрошеный элемент слабой типизации?» был порядком поражен, как ошибочностью данного подхода, так и тем, что никто не обратил на это внимание.

Автор поста приводит идею того, что способ, возвращающий ссылочный тип, объект которого создается из некоторого репозитория, должен, тем либо другим образом, гарантировать, что возвращаемый объект не будет null. При этом в одном из примеров он использует контракты, что противоречит их тезисам. Я хочу разобрать ошибочность этого подхода.

У нас есть способ GetItem, тот, что достает объект из некоторого репозитория и должен, по плану автора, гарантировать, что объект будет не null.

public Item GetItem(int itemId)
{
    return dataAccessor.getItemById(itemId);
}

В случае, если в репозитории не оказалось надобного объекта, dataAccessor вернет null, тот, что будет отдан заказчику и тот, не проверив значение на null, получит NullReferenceException. Так как-же дозволено гарантировать, что этого не произойдет?

Дозволено втиснуть проверку на null вовнутрь способа и в случае, если объект не обнаружен, кинуть Exception. Но этим мы легко переименовываем NullReferenceException в, к примеру, ItemNotFoundException. Больше того, сейчас заказчик обязан добавлять try-catch блок при всяком обращении к этому способу. Писатель заказчика будет дюже рад.

Еще вариант, это добавить пост-условие в способ. Вот так:

public Item GetItem(int itemId)
{
    Contract.Ensures(Contract.Result<Item>() != null);

    return dataAccessor.GetItemById(itemId);
}

Здесь все становится вовсе нехорошо и котят в мире становится поменьше. Прочитав контракт, всякий человек должен осознать, что данный способ вернет объект неизменно, при любом предоставленном идентификаторе. Но это немыслимо. Способ не может гарантировать, что объект с этим Id есть в репозитории. Значит необходимо добавить пред-условие, которое поможет бедолаге и спихнет все задачи заказчику:

public Item GetItem(int itemId)
{
    Contract.Requires(dataAccessor.GetItemById(itemId) != null)
    Contract.Ensures(Contract.Result<Item>() != null);

    return dataAccessor.GetItemById(itemId);
}

Радостно, не правда ли? Что бы достать объект из репозитория, необходимо вначале вытянуть объект из репозитория, для чего необходимо вытянуть объект из репозитория, для чего…

Правда в том, что ложки нет никто не может гарантировать существование объекта в репозитории. Исключительный метод гарантировать существование всякого объекта это сделать его и зажать его ссылку. Все остальное – дрянный дизайн. Data access layer должен достать объект из репозитория и передать заказчику. Он не знает как обработать неимение объекта и вообще не в курсе нехорошо ли это. За это отвечает ярус логики.

Неосуществимость гарантировать существования объекта вне поля видимости, приводит ко 2-й идее приведенной в статье по ссылке вверху. Применение nullable контейнера для ссылочных типов. Я перефразирую: nullable reference. Масло масляное. Было необычно узнать про знаменитость этого паттерна.

Ссылочный тип может ссылаться на null. Для чего засовывать один ссылочный тип в иной и добавлять в контейнер качество HasValue, для меня бесстрашно не ясно. Для проверки на HasValue? Что мешает обратится к содержимому объекту без этой проверки? Дозволено верно так-же безалаберно не проверить на null через неравенство. Больше того, данный паттерн не только непотребен, но и пагубен. Взгляните на дальнейший код:

public Maybe<Item> SomeMethod()
{
    var mbItem = GetMbItem();

    if(mbItem.HasValue)
    {
        var item = mbItem.Value;

        ModifyItem(ref item); 
    }

    return mbItem;
}

В случае если способ ModifyItem подменил объект, то способ SomeMethod вернет контейнер со ветхим объектом. Иди потом, ищи данный баг.

В всеобщем, я считаю практику, показанную в той статье, пагубной. Для проверки ссылки на null, в C# есть типовые средства, а для того, Дабы не допускать NullReferenceException, необходимо быть внимательным. Усложнять систему для этого вовсе необязательно. Работая с репозиториями необходимо следить за целостностью данных и от этого не убежишь. Если в репозитории нет объекта, тот, что там обязательно должен быть, это гораздо-гораздо дрянней.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB