Verificando se um objeto é nulo em C #


226

Eu gostaria de impedir um processamento adicional em um objeto se ele for nulo.

No código a seguir, verifico se o objeto é nulo por:

if (!data.Equals(null))

e

if (data != null)

No entanto, recebo um NullReferenceExceptionem dataList.Add(data). Se o objeto fosse nulo, ele nunca deveria ter inserido a ifinstrução-!

Portanto, estou perguntando se essa é a maneira correta de verificar se um objeto é nulo:

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

Se esta é a maneira correta de verificar se o objeto é nulo, o que estou fazendo de errado (como posso impedir um processamento adicional no objeto para evitar a NullReferenceException)?


13
Você também deve usar throw e;versusthrow new Exception(e.ToString());
Nix

17
em C #, você sempre deve usar != nullem suas verificações nulas. .Equalssempre lançará uma exceção se o objeto for nulo.
Kyle Trauberman

42
@ Nix: throw e;não é muito melhor. throw;, por outro lado ...
Jon

4
@ developer: e.ToString()produzirá uma string que inclui não apenas a mensagem de erro, mas também as de todos InnerExceptionse o rastreamento da pilha. Então essa é uma mensagem de exceção muito pesada. Se você (com razão!) Deseja preservar essas informações e manter onde elas pertencem, use simplesmente throw;.
Jon

14
A tentativa / captura não faz nada no momento. Todo mundo está dizendo apenas use "throw", mas se você não estiver fazendo nada com a exceção de repeti-la, por que ter um bloco try / catch? Geralmente, você captura exceções para lidar com elas normalmente, limpa os recursos (melhor com a cláusula "finalmente") ou faz algum tipo de registro antes de lançar a exceção. Nada disso está acontecendo neste código, portanto, não há necessidade de tentativa / captura.
David Peterson

Respostas:


252

Não é dataisso null, mas dataList.

Você precisa criar um com

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

Ainda melhor: como é um campo, faça-o private. E se não houver nada impedindo você, faça isso também readonly. Apenas boas práticas.

a parte, de lado

A maneira correta de verificar a nulidade é if(data != null). Esse tipo de verificação é onipresente para tipos de referência; até Nullable<T>substitui o operador de igualdade por ser uma maneira mais conveniente de expressarnullable.HasValue ao verificar a nulidade.

Se você o fizer if(!data.Equals(null)), receberá um NullReferenceExceptionifdata == null . O que é meio cômico, já que evitar essa exceção era o objetivo em primeiro lugar.

Você também está fazendo isso:

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

Definitivamente, isso não é bom. Eu posso imaginar que você o coloque lá apenas para poder entrar no depurador enquanto ainda estiver dentro do método; nesse caso, ignore este parágrafo. Caso contrário, não pegue exceções por nada. E se o fizer, repita-as usando apenas throw;.


5
Também vi Object.ReferenceEquals (obj, null) para esse fim. É para evitar substituições de igualdade?
Luca

2
@LucaPiccioni Eu usei-o para evitar valor-type-reclama quando usando os genéricos: geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
Eu prefiro null != data. Colocar a constante primeiro transforma o erro de digitação null = datano erro do compilador em vez de uma atribuição não intencional. (Também funciona para ==.)
jpmc26 27/06

6
@ jpmc26: No C # if (data = null)já é um erro de tempo de compilação, por isso, mesmo que demorasse décadas para chegar lá, não precisamos mais ficar atentos a isso. Até os compiladores C ++ produzirão facilmente um aviso sobre possível atribuição não intencional para esse código.
Jon

Luca, você também pode evitar substituições de igualdade convertendo para 'objeto' no teste. Do mesmo modo, esta resposta deve reivindicar isso: "if ((object) data! = Null)", pois evita erros quando a igualdade foi ultrapassada.
DAG

81

em C #> 7.0 use

if (obj is null) ...

Isso ignorará qualquer == ou! = Definido pelo objeto (a menos que você queira usá-lo ...)

Para uso não nulo if (obj is object)(ou if (!(obj is null)))


1
Gostaria de saber se existe um "não é nulo"? (python diria obj is not null)
sehe 07/07

1
Por que isso é melhor do que se que é mais legível (obj! = Null)
Orn Kristjansson

38
Gostaria que eles implementassem if (obj aint null):(
Nick Bull

10
Pois não é nulo, existe #if (obj is object)
yatskovsky 18/10/19

3
@OrnKristjansson porque! = E == podem ser substituídos.
precisa

61

C # 6 tem verificação nula monádica :)

antes:

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

depois de:

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

7
Porque "os comentários só podem ser editados por 5 minutos"? Que? De qualquer forma ... Como eu estava chegando lá ... eu vim aqui em busca de uma sintaxe melhor para expressar result = myObject == null ? null : myObject.SomePropertye seu exemplo me levou a escrever result = myObject?.SomeProperty. Homem!! Isso é sorrateiro. Eu ainda amo a codificação ...
Adam Cox

27

Seu dataList é nulo, pois não foi instanciado, a julgar pelo código que você postou.

Experimentar:

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
Além disso, apenas para adicionar, se os dados forem nulos, eles não travarão, você poderá adicionar nulos a uma Lista <Objeto>.
DaveShaw

7
Mas tentar fazer .Equals em um null lançaria uma exceção. Deve fazer! =
Null

@glosrob: Ah !! Que supervisão! Eu estava pensando que o NullReferenceException era do objeto .. não da lista! Eu sou novo em c # e achei que havia uma maneira especial de verificar nulo em c #!
desenvolvedor

Isso também, mas vi que Ed S. havia coberto.
DaveShaw

1
@ DaveShaw: Obrigado pela atenção. No entanto, quero evitar que um objeto nulo seja adicionado para processamento posterior, por isso ainda farei uma verificação. :)
desenvolvedor

19

[Editado para refletir a dica de @ kelton52]

Maneira mais simples é fazer object.ReferenceEquals(null, data)

Como (null==data)NÃO é garantido que funcione:

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

Produz:

Comparando '' com 'Nully'

Verdade

Falso


1
Na verdade, eu apenas tentei isso, e a observação 'A vantagem implícita é que ele ignora quaisquer substituições que possam estar presentes na classe de dados, como "operador! =".' Não parece ser verdade.
9558 Kelly Elton #

9

Não, você deveria estar usando !=. Se, datana verdade, for nulo, seu programa irá travar com NullReferenceExceptionum resultado da tentativa de chamar o Equalsmétodo null. Perceba também que, se você deseja verificar especificamente a igualdade de referência, deve usar o Object.ReferenceEqualsmétodo como nunca sabe como Equalsfoi implementado.

Seu programa está travando porque dataListé nulo, pois você nunca o inicializa.


7

O problema neste caso não dataé que seja nulo. É que dataListele próprio é nulo.

No local em que você declara, dataListvocê deve criar um novo Listobjeto e atribuí-lo à variável.

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

5

Além da resposta de Joseph Ortega , é melhor usar o método de extensão

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

E use o IsNullmétodo para todos os objetos como:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }

1
Por que return T == null ? true : false;e não apenas return T == null;?
Md2perpe 23/03/19

1
Não tenho certeza se concordo. Parece estranho chamar um método em um objeto para verificar se ele é nulo. Sem saber que era um método de extensão, você pensaria que lançaria uma exceção de referência nula.
21318 Jamie Twells

Pode confirmar totalmente que Jamie está correto - isso não vai funcionar. Eu sei porque eu tive um momento enlouquecido e escrevi um método de extensão semelhante: P O código sempre lançava uma exceção de referência nula, absolutamente não entra no método de extensão.
James King

Na verdade, quero dizer que você pode fazer isso com o método de extensão ... pode ser que o código tenha algum problema e possa melhorar!
Ali

Você pode chamar um método de extensão em um objeto nulo; você só precisa comparar T (neste caso) com nulo para ter cuidado. Jamie está certo, porém, parece estranho.
Tim Barrass

3

A partir do C # 8, você pode usar o padrão de propriedade 'vazio' (com correspondência de padrão ) para garantir que um objeto seja não nulo:

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

Essa abordagem significa " se o objeto faz referência a uma instância de algo " (ou seja, não é nulo).

Você pode pensar nisso como o oposto de: if (obj is null)... . que retornará true quando o objeto não fizer referência a uma instância de algo.

Para mais informações sobre padrões em C # 8.0, leia aqui .


3

A partir do C # 9, você pode fazer

if (obj is null) { ... }

Para uso não nulo

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

Se você precisar substituir esse comportamento, use ==e de !=acordo.


2

Jeffrey L. Whitledge está certo. Seu próprio objeto `dataList´ é nulo.

Também há outro problema com o seu código: você está usando a palavra-chave ref, o que significa que os dados do argumento não podem ser nulos! O MSDN diz:

Um argumento passado para um parâmetro ref deve primeiro ser inicializado. Isso difere de fora, cujos argumentos não precisam ser explicitamente inicializados antes de serem passados

Também não é uma boa ideia usar genéricos com o tipo `Objeto '. Os genéricos devem evitar o boxe / desembalagem e também garantir a segurança do tipo. Se você deseja um tipo comum, torne seu método genérico. Finalmente, seu código deve ficar assim:

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

Como outros já apontaram, não é, datamas é bem provável dataListque seja null. Além disso...

catch- throwé um antipadrão que quase sempre me dá vontade de vomitar toda vez que o vejo. Imagine que algo dê errado no fundo de algo que doOtherStuff()chama. Tudo o que você recebe de volta é um Exceptionobjeto, jogado throwna entrada AddData(). Sem rastreamento de pilha, sem informações de chamada, sem estado, nada para indicar a fonte real do problema, a menos que você entre e alterne seu depurador para interromper a exceção lançada em vez da exceção não tratada. Se você está capturando uma exceção e apenas a reproduzindo de alguma forma , principalmente se o código no bloco try não for trivial, faça um favor a si mesmo (e a seus colegas, presente e futuro) e jogue fora todotry - catchbloco . Concedido,throw;é melhor do que as alternativas, mas você ainda está dando a si mesmo (ou a quem quer que esteja tentando corrigir um bug no código) dores de cabeça completamente desnecessárias. Isso não quer dizer que o try-catch-throw seja necessariamente ruim por si só, desde que você faça algo relevante com o objeto de exceção lançado dentro do bloco catch.

Depois, existem os possíveis problemas de captura Exceptionem primeiro lugar, mas isso é outra questão, principalmente porque nesse caso em particular você lança uma exceção.

Outra coisa que me parece mais do que um pouco perigosa é que datapoderia potencialmente alterar valor durante a execução da função, já que você está passando por referência. Portanto, a verificação nula pode passar, mas antes que o código faça algo com o valor, ele é alterado - talvez para null. Não tenho certeza se isso é uma preocupação ou não (pode não ser), mas parece que vale a pena prestar atenção.


2
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

usar:

isnull(object.check.it)

Uso condicional:

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

Atualização (outra maneira) atualizada em 31/08/2017. Obrigado pelo comentário.

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

5
cond ? true : false;é completamente equivalente a apenas cond. Isso não acrescenta nada.
lericson

Sinto muito, mas se você verificar a função, ela deve retornar um valor bool. Eu estou fazendo o formalismo. Então, verifique novamente
Jose Ortega

3
ele quer dizer return T == null;também retorna um booleano!
MQoder

Eu sei o que ele está dizendo. ty
Jose Ortega

1
Em vez de return T == null ? true : false;apenas usar return T == null;.
Md2perpe

1

Sempre que você estiver criando objetos da classe, verifique se o objeto é nulo ou não usando o código abaixo.

Exemplo: object1 é objeto da classe

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

0

Eu apenas segui um método que normalmente seguiríamos no script java. Para converter objeto em string e verifique se eles são nulos.

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

0

Eu fiz mais simples (maneira positiva) e parece funcionar bem.

Como qualquer tipo de "objeto" é pelo menos um objeto


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.