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.