Comprobando si un objeto es nulo en C #

226

Me gustaría evitar un mayor procesamiento en un objeto si es nulo.

En el siguiente código verifico si el objeto es nulo por cualquiera de los dos:

if (!data.Equals(null))

y

if (data != null)

Sin embargo, recibo un NullReferenceExceptionat dataList.Add(data). Si el objeto era nulo, ¡nunca debería haber ingresado en la ifdeclaración!

Por lo tanto, pregunto si esta es la forma correcta de verificar si un objeto es 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;
}

Si esta es la forma correcta de verificar si el objeto es nulo, ¿qué estoy haciendo mal (¿cómo puedo evitar un mayor procesamiento en el objeto para evitar la NullReferenceException)?

desarrollador
fuente
13
También deberías usar throw e;versusthrow new Exception(e.ToString());
Nix
17
en C # siempre debe usar != nullen sus cheques nulos. .Equalssiempre lanzará una excepción si el objeto es nulo.
Kyle Trauberman
42
@Nix: throw e;no es mucho mejor. throw;, por otro lado ...
Jon
44
@developer: e.ToString()producirá una cadena que incluye no solo el mensaje de error, sino también los de todos InnerExceptionsy el seguimiento de la pila. Entonces ese es un tipo de mensaje de excepción muy pesado. Si usted (¡con razón!) Desea preservar esta información y mantenerla donde pertenece, úsela simplemente throw;.
Jon
14
El try / catch no hace nada por el momento. Todo el mundo dice simplemente usar "tirar", pero si no estás haciendo nada con la excepción, sino volver a tirarlo, ¿por qué tener un bloque try / catch? Por lo general, detecta excepciones para manejarlas con gracia, limpiar recursos (mejor con la cláusula "finalmente") o hacer algún tipo de registro antes de volver a lanzar la excepción. Ninguno de estos está sucediendo en este código, por lo que no hay necesidad de probar / atrapar en absoluto.
David Peterson

Respuestas:

252

No es dataeso null, pero dataList.

Necesitas crear uno con

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

Aún mejor: como es un campo, hazlo private. Y si no hay nada que te impida, hazlo también readonly. Solo una buena práctica.

Aparte

La forma correcta de verificar la nulidad es if(data != null). Este tipo de verificación es omnipresente para los tipos de referencia; incluso Nullable<T>anula el operador de igualdad para ser una forma más conveniente de expresar nullable.HasValuecuando se verifica la nulidad.

Si lo haces if(!data.Equals(null)), obtendrás un NullReferenceExceptionif data == null. Lo cual es bastante cómico ya que evitar esta excepción fue el objetivo en primer lugar.

También estás haciendo esto:

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

Esto definitivamente no es bueno. Me imagino que lo pones allí solo para que puedas entrar al depurador mientras aún estás dentro del método, en cuyo caso ignora este párrafo. De lo contrario, no atrape excepciones para nada. Y si lo hace, vuelva a lanzarlos usando solo throw;.

Jon
fuente
55
También he visto Object.ReferenceEquals (obj, null) para este propósito. ¿Es para evitar anulaciones de igualdad?
Luca
2
@LucaPiccioni Lo he usado para evitar quejas de tipo de valor cuando uso genéricos: geekality.net/2009/11/13/generics-and-checking-for-null
Svish
44
Yo prefiero null != data. Poner la constante primero convierte el error tipográfico de bonehead null = dataen un error del compilador, en lugar de una asignación no intencional. (También funciona para ==.)
jpmc26
66
@ jpmc26: En C # if (data = null)ya hay un error de tiempo de compilación, por lo que incluso si tardó décadas en llegar allí, ya no necesitamos tener cuidado con eso. Incluso los compiladores de C ++ generarán fácilmente una advertencia sobre la posible asignación no intencionada de ese código.
Jon
Luca, también puedes evitar anulaciones de igualdad al lanzar a 'objeto' en la prueba. En una línea similar, esta respuesta debería afirmar esto en su lugar: "if ((object) data! = Null)" ya que evita errores cuando se ha anulado la igualdad.
DAG
82

en C #> 7.0 uso

if (obj is null) ...

Esto ignorará cualquier == o! = Definido por el objeto (a menos, por supuesto, que desee usarlos ...)

Para uso no nulo if (obj is object)(o if (!(obj is null)))

kofifus
fuente
1
Me pregunto ¿hay un "no es nulo"? (Python diría obj is not null)
sehe
1
¿Por qué es eso mejor que si (obj! = Nulo) que es más legible
Orn Kristjansson
38
Ojalá lo implementaran if (obj aint null):(
Nick Bull
10
Porque no es nulo hayif (obj is object)
yatskovsky
3
@OrnKristjansson porque! = Y == pueden anularse.
mitchellJ
61

C # 6 tiene una comprobación nula monádica :)

antes de:

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

después:

var bestValue = points?.FirstOrDefault()?.X ?? -1;
Jowen
fuente
77
¿Porque "los comentarios solo pueden editarse durante 5 minutos"? ¿Qué? De todos modos ... Cuando estaba llegando ... Vine aquí en busca de una mejor sintaxis para expresar result = myObject == null ? null : myObject.SomePropertyy su ejemplo me avisó para escribir result = myObject?.SomeProperty. ¡¡Hombre!! Eso es astuto. Todavía me encanta codificar ...
Adam Cox
27

Su dataList es nula ya que no se ha instanciado, a juzgar por el código que ha publicado.

Tratar:

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;

}

glosrob
fuente
3
Además, solo para agregar, si los datos son nulos, no se bloquearán, puede agregar nulos a una Lista <Objeto>.
DaveShaw
77
Pero tratar de hacerlo. Igual en un nulo arrojaría una excepción. Debe hacer! = Nulo
glosrob
@glosrob: ¡Ah! ¡Qué descuido! Estaba pensando que la NullReferenceException era del objeto ... ¡no de la lista! ¡Soy nuevo en c # y pensé que había una forma especial de verificar nulo en c #!
desarrollador
Eso también, pero vi que Ed S. lo había cubierto.
DaveShaw
1
@DaveShaw: Gracias por el aviso. Sin embargo, quiero evitar que se agregue un objeto nulo para un procesamiento posterior, por lo que aún haré una comprobación. :)
desarrollador
19

[Editado para reflejar una pista de @ kelton52]

La manera más simple es hacer object.ReferenceEquals(null, data)

Como (null==data)NO se garantiza 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));
}

Produce:

Comparando '' con 'Nully'

Cierto

Falso

gatopeich
fuente
1
En realidad, acabo de intentar esto y la observación 'La ventaja implícita es que ignora cualquier anulación que pueda estar presente en la clase de datos, como "operator! =". No parece ser cierto.
Kelly Elton
9

No, deberías estar usando !=. Si datarealmente es nulo, entonces su programa simplemente se bloqueará con un NullReferenceExceptioncomo resultado de intentar activar el Equalsmétodo null. También tenga en cuenta que, si desea verificar específicamente la igualdad de referencia, debe usar el Object.ReferenceEqualsmétodo ya que nunca sabe cómo Equalsse ha implementado.

Su programa se bloquea porque dataListes nulo ya que nunca lo inicializa.

Ed S.
fuente
7

El problema en este caso no dataes que sea ​​nulo. Es que en dataListsí mismo es nulo.

En el lugar donde declara dataList, debe crear un nuevo Listobjeto y asignarlo a la variable.

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

Además de la respuesta de @Jose Ortega , es mejor usar el método de extensión

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

Y use el IsNullmétodo para todos los objetos como:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }
Ali
fuente
1
¿Por qué return T == null ? true : false;y no solo return T == null;?
md2perpe el
1
No estoy seguro de estar de acuerdo. Parece extraño estar llamando a un método en un objeto para verificar si es nulo. Sin saber que era un método de extensión, pensaría que arrojaría una excepción de referencia nula.
Jamie Twells
Puedo confirmar totalmente que Jamie está en lo correcto, esto no funcionará. Lo sé porque tuve un momento de cerebro de liebre y escribí un método de extensión similar: P El código siempre arrojó una excepción de referencia nula, absolutamente no entrará en el método de extensión.
James King
Realmente quiero decir que puedes hacerlo con el método de extensión ... ¡puede que el código tenga algún problema y pueda mejorar!
Ali
Puede llamar a un método de extensión en un objeto nulo; solo necesita comparar T (en este caso) contra nulo para tener cuidado. Jamie tiene razón, sin embargo, parece extraño.
Tim Barrass
3

A partir de C # 8 , puede usar el patrón de propiedad 'vacío' (con coincidencia de patrones ) para asegurarse de que un objeto no sea nulo:

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

Este enfoque significa " si el objeto hace referencia a una instancia de algo " (es decir, no es nulo).

Se puede pensar en esto como lo opuesto a: if (obj is null).... que devolverá verdadero cuando el objeto no haga referencia a una instancia de algo.

Para obtener más información sobre patrones en C # 8.0, lea aquí .

Darren Ruane
fuente
3

A partir de C # 9 puedes hacer

if (obj is null) { ... }

Para uso no nulo

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

Si necesita anular este comportamiento, use ==y en !=consecuencia.

Eugene Chybisov
fuente
2

Jeffrey L Whitledge tiene razón. Su `dataList´-Object en sí mismo es nulo.

También hay otro problema con su código: está utilizando la palabra clave ref, lo que significa que los datos del argumento no pueden ser nulos. El MSDN dice:

Primero se debe inicializar un argumento pasado a un parámetro ref. Esto difiere de fuera, cuyos argumentos no tienen que inicializarse explícitamente antes de pasarlos

Tampoco es una buena idea usar genéricos con el tipo `Objeto´. Los genéricos deben evitar el boxeo / desempaquetado y también garantizar la seguridad del tipo. Si desea un tipo común, haga que su método sea genérico. Finalmente su código debería verse así:

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) {
        //...
      }
    }
DiableNoir
fuente
2

Como otros ya han señalado, no lo es, datapero es muy probable dataListque así sea null. Además de eso...

catch- throwEs un antipatrón que casi siempre me da ganas de vomitar cada vez que lo veo. Imagina que algo sale mal en algo que doOtherStuff()llama. Todo lo que se obtiene es un Exceptionobjeto, lanzado en el throwen AddData(). Sin seguimiento de la pila, sin información de llamadas, sin estado, nada en absoluto para indicar la fuente real del problema, a menos que entre y cambie su depurador para interrumpir la excepción lanzada en lugar de la excepción no controlada. Si tienes que coger una excepción y sólo re-lanzando que de ninguna manera , sobre todo si el código en el bloque try es de ninguna manera no trivial, hacer usted mismo (y sus colegas, presente y futuro) un favor y echar un vistazo a la totalidad try- catchbloque . Concedido,throw;es mejor que las alternativas, pero todavía te estás dando a ti mismo (o a quien sea que esté tratando de corregir un error en el código) dolores de cabeza completamente innecesarios. Esto no quiere decir que try-catch-throw sea necesariamente malo per se, siempre que haga algo relevante con el objeto de excepción que se arrojó dentro del bloque catch.

Luego están los posibles problemas de la captura Exceptionen primer lugar, pero ese es otro asunto, particularmente porque en este caso particular lanzas una excepción.

Otra cosa que me parece más que un poco peligrosa es que datapotencialmente podría cambiar el valor durante la ejecución de la función, ya que está pasando por referencia. Por lo tanto, la verificación nula puede pasar, pero antes de que el código haga algo con el valor, cambia, quizás a null. No estoy seguro de si esto es una preocupación o no (puede que no lo sea), pero parece que vale la pena tenerlo en cuenta.

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

utilizar:

isnull(object.check.it)

Uso condicional:

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

Actualización (otra forma) actualizada 31/08/2017. Gracias por el comentario.

public static bool isnull(object T)
{
    return T ? true : false;
}
Jose Ortega
fuente
55
cond ? true : false;es completamente equivalente a solo cond. Esto no agrega nada.
lericson
Lo siento, pero si marca la función, debe devolver un valor bool. Estoy haciendo el formalismo. Así que vuelva a verificarlo
Jose Ortega
3
él quiere decir return T == null;también devuelve un booleano!
MQoder
Sé lo que está diciendo. ty
Jose Ortega
1
En lugar de return T == null ? true : false;solo usar return T == null;.
md2perpe el
1

Siempre que esté creando objetos de clase, debe verificar si el objeto es nulo o no utilizando el siguiente código.

Ejemplo: object1 es objeto de clase

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

Simplemente seguí un método que generalmente seguiríamos en Java Script. Para convertir objetos en cadenas y luego verificar si son nulos.

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

Lo hice más simple (forma positiva) y parece funcionar bien.

Dado que cualquier tipo de "objeto" es al menos un objeto


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
Gilles5678
fuente