>
>
>
V3111. Checking value for null will alw…


V3111. Checking value for null will always return false when generic type is instantiated with a value type.

Анализатор обнаружил, что значение, имеющее обобщённый (generic) тип, сравнивается с 'null'. Если обобщённый тип никак не ограничен, то он может быть инстанциирован как значимым, так и ссылочным типом. В случае если он окажется значимым, проверка на 'null' всегда будет возвращать 'false', так как значимые типы не могут принимать нулевое (null) значение.

Рассмотрим пример.

class Node<T>
{
  T value;
  void LazyInit(T newValue)
  {
    if (value == null) // <=
    {
      value = newValue;
    }
  }
}

В случае если тип 'T' будет определен как значимый, тело условия 'if' никогда не выполнится. В нашем примере это приведёт к тому, что переменная 'value' не будет проинициализирована переданным значением - её значение всегда останется равным 'default' значению 'T'.

Если необходимо обрабатывать объекты только ссылочного типа, то используйте ограничители. К примеру, generic тип 'T' из примера выше может быть ограничен только для ссылочных типов:

class Node<T> where T : class // <=
{
  T value;
  void LazyInit(T newValue)
  {
    if (value == null) 
    {
      value = newValue;
    }
  }
}

Если же generic тип должен принимать как значимые, так и ссылочные типы, и проверка должна осуществляться для обоих видов значений, то тогда необходимо использовать проверку на значение данного типа по умолчанию (default), вместо проверки на 'null':

class Node<T>
{
  T value;
  void LazyInit(T newValue)
  {
    if (object.Equals(value, default(T))) // <=   
    {
      value = newValue;
    }
  }
}

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

class Node<T>
{
  T value;
  void LazyInit(T newValue)
  {
    if (typeof(T).IsClass && // <=   
        object.Equals(value, default(T))) 
    {
      value = newValue;
    }
  }
}

Метод 'IsClass' вернет 'true' если generic был инстанциирован ссылочным типом. Таким образом, проверка на значение по умолчанию будет происходить только для ссылочных типов, по аналогии с предыдущим примером.