Re[2]: 2 Nuald: Один вопрос
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.09.06 12:44
Оценка:
Здравствуйте, Nuald, Вы писали:

N>В некоторых случаях там действительно может прийти null. Может прийти и пустая строка. Use-case сценарий приводить не буду, но пару раз ловил исключения при тестировании. Проверки я ставил только там, где есть смысл.


Не, не. Надо четко понимать зачем там приходит null. По логике этих методов вроде бы никакие пустые строки там быть не должны.

VD>>Если на оба последних вопроса ответ отрицательный, и этот код создан для чистоты, так сказать, то будь добр, замени его на генерацию исключений ArgumentNullException/ArgumentException.


N>Хм, может лучше ассерты?


Нет, лучше исключения. Что программа будет делать после того как этот ассерт закроется? Как продолжить работу в этой ситуации? Ведь на null и пустые строки там рассчета нет.

N>Если разработчик точно уверен, что в этом методе не придет null, тогда он ставит Debug.Assert.


Нет, см. выше. Конечно все проверки — это вообще сфера предпочтений и стратегий, но у нас принята стратегия в которой Assert и темболее Debug... ставится для того чтобы проверить свои предполжения. А когда ты пишишь метод который может быть вызван черт знает откуда, черт знает кем, то неверные входные условия являются исключительной ситуацией для функции, а значит должны генерировать исключения.

Исключения выгдны еще и тем, что в релизе они позволят востановиться до работоспосбного состояния. Ассерты же будут только досождать пользователю своими окнами. За ними будут появляться исключения, только уже менее информативные.

N> Я так глубоко не копал, чтобы точно знать, какие данные передаются в методы.


Темболее странно в таких условиях лепить if-ы замазывающие аварийные ситуации.

N> Поиск по вызывающим функциям показал, что вполне могут приходить некорректные строки.


Конкретнее пожалуйста. Что значит "некорретные"? И в следствии чего они могут приходить.

Еще раз повторю. Никаких замазываний проблем. Или это штатное поведение метода продиктованное проектным решением, или там обязан быть ассер. Уж лучше никакой обработки чем такая.

N>Ага, и в итоге блок if-a вообще становится незаметным в общем объеме кода.


Понимаеш ли в чем дело. Это не обсуждается. Это правила форматирования принятые в проекте. Фигурные скобки ставятся тольк для случаев когда есть более одного statment-а и возможно когда есть многострочное условие if-а и его тело плохо различимо.

N> Странно, почему вы тогда не используете форматирование K&R


Потому что по принятому у нас стилю оформления кода. Фигурные скобки ставятся всятся на новой строке.

N>P.S. Все-таки не понимаю, к чему придирки к проверкам?


Это очень плохо что не понимаешь. Я попытался обяснить. Посторайся понять. Основная причина — такие проекри могу скрыть реальные ошибки и превратить их из ошибок приводящих к исключению (кторое легко отслеживается) к ошибкам в логике работы программы (которые ловятся и исправляются намного сложнее).

N> Сами же сказали, что код находится на еще очень ранней стадии.


Это не повод писать код от балды.

N> Я отловил пару раз NullReferenceException и поставил проверки.


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

ОК, если не понимаешь, давай разберем конкретные случаи:
if (!String.IsNullOrEmpty(location))
    _projectLocation = location;
else
    _projectLocation = Path.GetDirectoryName(fileName);

Здесь можно сказать все ОК. Только зачем делать отрицающее условие? Оно усложняет чтение. В таких случаях нужно писать:
if (String.IsNullOrEmpty(location))
    _projectLocation = Path.GetDirectoryName(fileName);
else
    _projectLocation = location;

Отрицающие условия хуже читаются и в if/else и ?: их лучше не использовать.

public bool IsFileInProject(string filePath)
{
    if (String.IsNullOrEmpty(filePath))
    {
        return false;
    }
    return _filesMap.ContainsKey(filePath);
}

Вот здесь уже большой вопрос. Я не представляю себе шататной ситуации когда путь к файлу будет пустым. Хотя бы имя то у него должно быть? А раз так тут надо вставлять проверки с возбуждением исключеий. Или хотя бы ничего не делать.

Заметь, даже если не ставить проверки, то функция ContainsKey() класса Dictionary проверит аргументи и выдаст исключение ArgumentNullException. Твой же код скроет ошибку.

Если же у нас допустимы пустые имена файлов, то я хотел бы выслушать обоснование этого факта. Зачем это нужно, где и для чего используется.

public void UpdateFile(ParseRequest request)
{
    if (request == null)
    {
        return;
    }
    int    oldTimestamp;
    string filePath  = request.FileName;
    int    timestamp = request.Timestamp;

    if (!_filesMap.TryGetValue(filePath, out oldTimestamp))
        throw new ArgumentException("File '" + filePath + "' not found.", "filePath");

    if (timestamp != oldTimestamp)
    {
        Engine.Sources.AddOrUpdate(filePath, GetFileContent(request));
        _filesMap[filePath] = timestamp;
    }
}

А вот здесь на лицо явное замазывание ошибки. Если где-то произойдет ошибка и в request окажется null, то мы не узнаем о ней, так как твоя проверка скроет ошибку.
string GetFileContent(ParseRequest request)
{
    if (request == null)
    {
        return String.Empty;
    }
    string text = request.Text;

    if (String.IsNullOrEmpty(text))
        text = File.ReadAllText(request.FileName);

    return text;
}


Еще хуже! Здесь мы уже наверняка получим неверное поведение. Зачем нам пустая строка? null в request является ошибкой!

private static NemerleFileNodeProperties GetNodeProperties(IVsHierarchy hierarchy, uint itemID)
{
    if (hierarchy == null)
    {
        return new NemerleFileNodeProperties(null);
    }
    object propertyValue;
    int    hr = hierarchy.GetProperty(itemID, (int)__VSHPROPID.VSHPROPID_BrowseObject, out propertyValue);

    if (hr != VSConstants.S_OK)
        throw new ArgumentException("Can't obtain VSHPROPID_BrowseObject for item with ID " + itemID, "itemID");

    FileNodeProperties properties = propertyValue as FileNodeProperties;
    if (properties != null)
    {
        return new NemerleFileNodeProperties(properties.Node);
    }
    return new NemerleFileNodeProperties(null);
}


Тут не ясно. На лицо изменение поведения метода, но есть ли в этом смысл? Или это очередная замазка другой проблемы?

public static ProjectInfo FindProject(string fileName)
{
    if (String.IsNullOrEmpty(fileName))
    {
        return null;
    }
    foreach (ProjectInfo proj in _projectsInfos)
        if (proj.IsFileInProject(fileName))
            return proj;

    return null;
}


Здесь та же ситуация что и с IsFileInProject(). Вместо диагностики ошибки мы получим ее замазывание и будем часами искать ошибку.

N> Я еще не настолько разобрался в проекте, чтобы знать корень этого null-а, и поставил проверки, чтобы просто студия не вываливалась.


Ставить проверки чтобы что-то не вываливалось категорически не надо! Если ты не в силах понять причину проблемы, то просто опиши ее в этом форуме или добавь описание в баг-трекер. При этом обясни как воспроизвести эту ошибку. И тогда мы уже вместе решим что с ней делать.

N> Предложи мне другую стратегию разработки, и тогда я не буду так делать.


Стратегия проста. Баги надо устранять, а не замазывать. Любая провекра должна делаться обоснованно. Фраза "чтобы исключение не вылетала" не может быть обоснованием.

Сейчас у нас много ошибок, так как проект находится в стадии разработки. И нам очень важно, чтобы ошибки были как можно более легко выявляемы.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.