it-swarm.com.ru

Проверка, является ли объект нулевым в C #

Я хотел бы предотвратить дальнейшую обработку объекта, если он нулевой.

В следующем коде я проверяю, является ли объект нулевым, либо:

if (!data.Equals(null))

а также

if (data != null)

Тем не менее, я получаю NullReferenceException в dataList.Add(data). Если объект был нулевым, он никогда не должен был бы даже вводить оператор if-!

Таким образом, я спрашиваю, является ли это правильным способом проверки, является ли объект нулевым:

public List<Object> dataList;
public  bool AddData(ref Object data)
    bool success = false;
    try
    {
        // I've also used "if (data != null)" which hasn't worked either
        if (!data.Equals(null))
        {
           //NullReferenceException occurs here ...
           dataList.Add(data);
           success = doOtherStuff(data);
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.ToString());
    }
    return success;
}

Если это правильный способ проверить, является ли объект нулевым, что я делаю неправильно (как я могу предотвратить дальнейшую обработку объекта, чтобы избежать исключения NullReferenceException)?

180
developer

Это не data, а null, а dataList.

Вам нужно создать один с

public List<Object> dataList = new List<Object>();

Еще лучше: поскольку это поле, сделайте его private. И если ничто не мешает вам, сделайте это также readonly. Просто хорошая практика.

в сторону

Правильный способ проверки на ничтожность - это if(data != null). Этот вид проверки повсеместен для ссылочных типов; даже Nullable<T> переопределяет оператор равенства, чтобы быть более удобным способом выражения nullable.HasValue при проверке на ничтожность.

Если вы выполните if(!data.Equals(null)), вы получите NullReferenceException if data == null. Что довольно смешно, потому что в первую очередь целью было избежать этого исключения.

Вы также делаете это:

catch (Exception e)
{
    throw new Exception(e.ToString());
}

Это определенно не хорошо. Я могу себе представить, что вы положили его туда просто для того, чтобы вы могли взломать отладчик, оставаясь внутри метода, и в этом случае пропустите этот абзац. В противном случае, не ловите исключения ни за что. И если вы это сделаете, сбросьте их, используя только throw;.

224
Jon

C # 6 имеет монадическая проверка на ноль :)

до:

if (points != null) {
    var next = points.FirstOrDefault();
    if (next != null && next.X != null) return next.X;
}   
return -1;

после:

var bestValue = points?.FirstOrDefault()?.X ?? -1;
46
Jowen

Ваш dataList является нулевым, поскольку он не был создан, судя по коду, который вы опубликовали.

Пытаться:

public List<Object> dataList = new List<Object>();
public  bool AddData(ref Object data)
bool success = false;
try
{
    if (!data.Equals(null))   // I've also used if(data != null) which hasn't worked either
    {
       dataList.Add(data);                      //NullReferenceException occurs here
       success = doOtherStuff(data);
    }
}
catch (Exception e)
{
    throw new Exception(e.ToString());
}
return success;

}

27
glosrob

в C # 7 лучшее

if (obj is null) ...

Это будет игнорировать любые == или! = Определенные объектом (если, конечно, вы не хотите их использовать ...)

Для не равных вы можете if (!(obj is null)) (некрасиво)

23
kofifus

[Отредактировано, чтобы отразить подсказку @ kelton52]

Самый простой способ это сделать object.ReferenceEquals(null, data)

Поскольку (null==data) НЕ гарантированно работает:

class Nully
{
    public static bool operator ==(Nully n, object o)
    {
        Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
        return true;
    }
    public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
    var data = new Nully();
    Console.WriteLine(null == data);
    Console.WriteLine(object.ReferenceEquals(null, data));
}

Производит:

Сравнивая '' с 'Nully'

Правда

False

17
gatopeich

Нет, вы должны использовать !=. Если data на самом деле имеет значение null, то ваша программа просто аварийно завершит работу с NullReferenceException в результате попытки вызвать метод Equals для null. Также следует понимать, что если вы специально хотите проверить равенство ссылок, вам следует использовать метод Object.ReferenceEquals, поскольку вы никогда не знаете, как реализовано Equals.

Ваша программа падает, потому что dataList имеет значение null, поскольку вы никогда не инициализируете его.

9
Ed S.

Проблема в этом случае не в том, что data является нулевым. Дело в том, что само dataList является нулевым.

В месте, где вы объявляете dataList, вы должны создать новый объект List и назначить его переменной.

List<object> dataList = new List<object>();
6
Jeffrey L Whitledge

В дополнение к @ Jose Ortega ответу, его лучше использовать метод расширения

 public static bool IsNull(this object T)
     {
        return T == null;
     } 

И используйте метод IsNull для всех объектов, таких как:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }
5
Ali
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

использовать:

isnull(object.check.it)

Условное использование:

isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;

Обновление (другой способ) обновлено 31.08.2017. Спасибо за комментарий.

public static bool isnull(object T)
{
    return T ? true : false;
}
3
Jose Ortega

Джеффри Л. Уитледж прав. Ваш `dataList´-Object сам по себе равен нулю.

Есть и другая проблема с вашим кодом: вы используете ключевое слово ref, что означает, что данные аргумента не могут быть нулевыми! MSDN говорит:

Аргумент, передаваемый параметру ref, должен сначала быть инициализирован. Это отличается от того, чьи аргументы не нужно явно инициализировать перед передачей

Также не очень хорошая идея использовать дженерики с типом `Object´. Дженерики должны избегать бокса/распаковки, а также обеспечивать безопасность типов. Если вы хотите общий тип, сделайте ваш метод универсальным. Наконец ваш код должен выглядеть так:

public class Foo<T> where T : MyTypeOrInterface {

      public List<T> dataList = new List<T>();

      public bool AddData(ref T data) {
        bool success = false;
        try {
          dataList.Add(data);                   
          success = doOtherStuff(data);
        } catch (Exception e) {
          throw new Exception(e.ToString());
        }
        return success;
      }

      private bool doOtherStuff(T data) {
        //...
      }
    }
2
DiableNoir

Как уже отмечали другие, это не data, а скорее dataList, то есть null. В дополнение к этому...

catch-throw - это антипаттерн, который почти всегда вызывает у меня желание вырвать каждый раз, когда я его вижу. Представьте, что что-то идет не так глубоко в чем-то, что вызывает doOtherStuff(). Все, что вы получите, это Exception объект, брошенный в throw в AddData(). Никакой трассировки стека, никакой информации о вызове, никакого состояния, вообще ничего, что бы указывало на реальный источник проблемы, если только вы не включите и не переключите свой отладчик, чтобы сломать исключение, а не обработанное исключение. Если вы перехватываете исключение и просто перебрасываете его любым способом, особенно если код в блоке try в любом случае нетривиален, сделайте себе (и своим коллегам, настоящим и будущим) услугу и выбросить весь блок try-catch. Конечно, throw; лучше, чем альтернативы, но вы все еще даете себе (или тому, кто пытается исправить ошибку в коде) совершенно ненужные головные боли. Это не означает, что try-catch-throw обязательно является злом само по себе, если вы делаете что-то релевантное с брошенным объектом исключения внутри блока catch.

Тогда есть потенциальные проблемы с перехватом Exception в первую очередь, но это другой вопрос, особенно потому, что в этом конкретном случае вы бросаете исключение.

Еще одна вещь, которая кажется мне более чем немного опасной, это то, что data потенциально может изменить значение во время выполнения функции, поскольку вы передаете по ссылке. Таким образом, нулевая проверка может пройти, но прежде чем код начнет что-либо делать со значением, он будет изменен - ​​возможно, на null. Я не уверен, если это беспокойство или нет (это может быть не так), но, похоже, стоит остерегаться.

2
a CVn

Всякий раз, когда вы создаете объекты класса, вы должны проверить, является ли объект нулевым или нет, используя приведенный ниже код.

Пример: object1 является объектом класса

void myFunction(object1)
{
  if(object1!=null)
  {
     object1.value1 //If we miss the null check then here we get the Null Reference exception
  }
}
1
user3483639