# 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 был инстанциирован ссылочным типом. Таким образом, проверка на значение по умолчанию будет происходить только для ссылочных типов, по аналогии с предыдущим примером.