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


226

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

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

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)?


13
Вы также должны использовать throw e;противthrow new Exception(e.ToString());
Nix

17
в C # вы всегда должны использовать != nullв своих нулевых проверках. .Equalsвсегда будет выдавать исключение, если объект нулевой.
Кайл Трауберман

42
@Nix: throw e;не намного лучше. throw;с другой стороны ...
Джон

4
@developer: e.ToString()создаст строку, которая включает в себя не только сообщение об ошибке, но также и все InnerExceptionsи трассировку стека. Так что это вроде очень толстого сообщения об исключении. Если вы (правильно!) Хотите сохранить эту информацию и сохранить ее, используйте просто throw;.
Джон

14
Try / catch ничего не делает в данный момент. Все говорят, что просто используйте «throw», но если вы ничего не делаете с исключением, а перекидываете его, зачем вообще использовать блок try / catch? Обычно вы ловите исключения, чтобы изящно обрабатывать их, очищать ресурсы (лучше с предложением «finally») или делать какую-то запись в журнал перед повторным вызовом исключения. Ничего из этого не происходит в этом коде, поэтому нет никакой необходимости в try / catch.
Дэвид Петерсон

Ответы:


252

Это не dataто есть null, но dataList.

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

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

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

В стороне

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

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

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

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

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


5
Я видел также Object.ReferenceEquals (obj, null) для этой цели. Это чтобы избежать переопределения равенства?
Лука

2
@LucaPiccioni Я использовал его для предотвращения жалоб типа-значения при использовании непатентованных средств: geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
Я предпочитаю null != data. Помещение константы первым превращает опечатку null = dataв ошибку компилятора, а не в непреднамеренное присваивание. (Также работает для ==.)
jpmc26

6
@ jpmc26: В C # if (data = null)уже есть ошибка времени компиляции, так что даже если бы потребовались десятилетия, чтобы добраться до нас, нам больше не нужно следить за этим. Даже компиляторы C ++ легко выдадут предупреждение о возможном непреднамеренном назначении этого кода.
Джон

Лука, ты также можешь избежать переопределения равенства, приведя к «объекту» в тесте. Аналогичным образом, этот ответ должен утверждать, что вместо этого: «if ((object) data! = Null)», поскольку он избегает ошибок, когда равенство было переопределено.
DAG

82

в C #> 7.0 использовать

if (obj is null) ...

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

Для ненулевого использования if (obj is object)(или if (!(obj is null)))


1
Интересно, есть "не нуль"? (сказал бы питон obj is not null)
сехе

1
Почему это лучше, чем если (obj! = Null), что более читабельно
Орн Кристьянссон

39
Хотелось бы, чтобы они реализовали if (obj aint null):(
Ник Булл,

10
Ибо не if (obj is object)
ноль

3
@OrnKristjansson, потому что! = И == могут быть переопределены.
mitchellJ

61

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;

7
Потому что «комментарии можно редактировать только в течение 5 минут»? Что? Во всяком случае ... Как я дошел до этого ... Я пришел сюда в поисках лучшего синтаксиса для выражения, result = myObject == null ? null : myObject.SomePropertyи ваш пример подсказал мне написать result = myObject?.SomeProperty. Мужчина!! Это подлый. Я все еще люблю кодировать ...
Адам Кокс

27

Ваш 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;

}


3
Кроме того, просто для добавления, если данные имеют нулевое значение, они не будут аварийно завершаться, вы можете добавить нулевое значение в список <Object>.
DaveShaw

7
Но попытка сделать .Equals на нуле выдаст исключение. Должен сделать! =
Null

@glosrob: Ах !! Какой недосмотр! Я думал, что NullReferenceException было от объекта .. не из списка! Я новичок в c #, и я подумал, что есть специальный способ проверки на ноль в c #!
разработчик

Это тоже, но я видел, что Эд С. покрыл это.
DaveShaw

1
@DaveShaw: Спасибо за внимание. Я хочу избежать добавления нулевого объекта для дальнейшей обработки, поэтому я все равно буду делать проверку. :)
разработчик

19

[Отредактировано, чтобы отразить подсказку @ 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'

Правда

Ложь


1
На самом деле я только что попробовал это, и замечание «Неявное преимущество заключается в том, что он игнорирует любые переопределения, которые могут присутствовать в классе данных, например« operator! = »». Кажется, не соответствует действительности.
Келли Элтон

9

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

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


7

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

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

List<object> dataList = new List<object>();

5

В дополнение к ответу @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 //
   }

1
Почему return T == null ? true : false;и не просто return T == null;?
md2perpe

1
Я не уверен, что согласен. Выглядит странно, что вызывается метод объекта, чтобы проверить, является ли он нулевым. Не зная, что это метод расширения, можно подумать, что он выдаст исключение нулевой ссылки.
Джейми Twells

Могу полностью подтвердить, что Джейми прав - это не сработает. Я знаю, потому что у меня был заяц-момент, и я написал похожий метод расширения: P Код всегда выдавал исключение нулевой ссылки, он абсолютно не входит в метод расширения.
Джеймс Кинг,

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

Вы можете вызвать метод расширения для нулевого объекта; вам просто нужно сравнить T (в этом случае) с нулем, чтобы быть осторожным. Джейми прав, хотя, это выглядит странно.
Тим Баррасс

3

Начиная с C # 8, вы можете использовать «пустой» шаблон свойства (с сопоставлением с шаблоном ), чтобы гарантировать, что объект не является нулевым:

if (obj is { })
{
    // 'obj' is not null here
}

Этот подход означает « если объект ссылается на экземпляр чего-либо » (т. Е. Он не равен нулю).

Вы можете думать об этом как противоположность: if (obj is null).... который вернет true, когда объект не ссылается на экземпляр чего-либо.

Подробнее о шаблонах в C # 8.0 читайте здесь .


3

Начиная с C # 9 вы можете сделать

if (obj is null) { ... }

Для ненулевого использования

if (obj is not object) { ... }

Если вам нужно переопределить это поведение, используйте ==и !=соответственно.


2

Джеффри Л. Уитледж прав. Ваш `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

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

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

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

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


2
  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;
}

5
cond ? true : false;полностью эквивалентно просто cond. Это ничего не добавляет.
lericson

Извините, но если вы проверите функцию, она должна вернуть значение bool. Я делаю формализм. Так что перепроверьте это
Хосе Ортега

3
он имеет в виду return T == null;также возвращает логическое значение!
MQoder

Я знаю, что он говорит. Ты
Хосе Ортега

1
Вместо того, чтобы return T == null ? true : false;просто использовать return T == null;.
md2perpe

1

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

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

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

0

Я просто следовал методу, которому мы обычно следовали в java-скрипте. Чтобы преобразовать объект в строку, а затем проверить, являются ли они нулевыми.

var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
  // code as per your needs
}

0

Я сделал более простой (позитивный способ), и, кажется, работает хорошо.

Поскольку любой вид «объекта» является, по крайней мере, объектом


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.