Почему resharper по-прежнему выдает предупреждения об нулевых ссылках для этого кода

Этот метод является обработчиком событий для OnRowCommand в элементе управления aspx GridView. Resharper предупреждает, что gvUnits, gvUnit.DataKeys и gvUnits.DataKeys[index] могут быть нулевыми, и предлагает добавить проверки во втором операторе if. После их добавления создается дополнительное предупреждение о том, что gvUnits.DataKeys != null всегда верно. Ни добавление этих проверок, как предлагалось, ни ручное добавление утверждений не подавляли предупреждения.

Я не понимаю, что здесь происходит: gvUnits volatile, и если да, то почему, это ошибка в resharper 5.1 или что-то еще происходит?

protected void GvUnitsRowCommand(object sender, System.Web.UI.WebControls.GridViewCommandEventArgs e)
{
    if (e.CommandName == "EditUnit")
    {
        int index = int.Parse(e.CommandArgument.ToString());
        if (gvUnits != null && gvUnits.DataKeys != null && gvUnits.DataKeys.Count > index)
        {
            Debug.Assert(gvUnits != null);
            Debug.Assert(gvUnits.DataKeys != null);
            Debug.Assert(gvUnits.DataKeys[index] != null);

            int unitID = (int)gvUnits.DataKeys[index].Value;
            //do stuff with unitID
        }
    }
}

person Dan Is Fiddling By Firelight    schedule 08.11.2011    source источник


Ответы (2)


Предполагая, что DataKeys является свойством, тогда gvUnits.DataKeys по сути является вызовом метода (вызовом геттера). Таким образом, если вы вызываете его дважды, нет гарантии, что он не вернет null при втором вызове. Аналогично, если DataKeys[index] является вызовом индексатора (а не доступом к массиву), это также вызов метода, который, как указано выше, может возвращать значение null при втором вызове. Единственный способ обеспечить гарантированное утверждение — сохранить результат каждого вызова в локальной переменной, а затем подтвердить, что локальное значение не равно нулю. Поскольку локальное значение не может меняться между использованиями, ReSharper знает, что оно безопасно.

Это один из тех случаев, когда вы делаете неявное предположение, даже не осознавая этого (что возвращаемое значение свойства не будет изменяться между вызовами). Вы можете подавить предупреждение комментарием, если хотите, вместо того, чтобы создавать локальная копия для утверждения, которое в основном навязывает предположение разработчику свойства (чтобы гарантировать неизменяемость между последовательными вызовами).

person Dan Bryant    schedule 08.11.2011
comment
Я проверил, и DataKeys — это свойство, доступ к которому осуществляется с помощью метода индексатора. Теперь это имеет смысл; Resharper мог бы быть немного умнее, чтобы не предлагать генерировать «исправление», которое не работает (v6 здесь лучше?). - person Dan Is Fiddling By Firelight; 08.11.2011

проверьте это: int.Parse и (int) потерпят неудачу, если null попробует ввести Convert.ToInt32

if (e.CommandName == "EditUnit")
{
    int index = Convert.ToInt32(e.CommandArgument);
    DataKey key = GridView1.DataKeys[index];
    if (key!=null)
    {
        int id = Convert.ToInt32(key.Value);
    }
}
person Damith    schedule 08.11.2011
comment
Resharper любит ваш код не больше, чем мой. Я думаю, у Дэна Брайанта есть правильное объяснение происходящему. - person Dan Is Fiddling By Firelight; 08.11.2011