Asegúrese de que un objeto no sea nulo

¿Cómo puedo asegurarme de que una determinada instancia de una clase nunca sea nula? Alguien me dijo que usara Debug.Assert () pero al hacerlo, solo me aseguraría de que el código funcione en modo de depuración, mientras que también quiero asegurarme de que la condición nunca sea nula en la versión.

Por ejemplo, en el pasado escribí código como:

public string MyString
{
get
{
    if(instance1.property1.Equals("bla"))
    {
        return bla; 
    }
}
}

Pero esto lanza una excepción si instance1 es nulo. Me gustaría evitar cometer tales errores y generar tales excepciones en el futuro.

Gracias,


consulte un ejemplo específico a continuación que ilustra el problema:

Tengo un método que autentica a los usuarios en función de las respuestas de un servidor. El método es este:

        /// <summary>
    /// attempts authentication for current user
    /// </summary>
    /// <returns></returns>
    public AuthResult CheckUser()
    {
        WebRequest request = WebRequest.Create(GetServerURI);
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";

        string postdata = "data=" + HttpUtility.UrlEncode(SerializeAuth());
        byte[] arr = Utils.AppDefaultEncoding.GetBytes(postdata);
        request.ContentLength = arr.Length;
        request.Timeout = Convert.ToInt32(TimeUtils.GetMiliseconds(10, TimeUtils.TimeSelect.Seconds));

        Stream strToWrite = request.GetRequestStream();
        strToWrite.Write(arr, 0, arr.Length);

        WebResponse response = request.GetResponse();
        using (Stream dataFromResponse = response.GetResponseStream())
        {
            using (StreamReader reader = new StreamReader(dataFromResponse))
            {
                string readObj = reader.ReadToEnd();
                return DeserializeAuth(readObj);
            }
        }
    }

para llamar a este método, uso

_authenticationResult = authObj.CheckUser();

También tengo esta propiedad, entre otras

        public ResultType AuthResult
    {
        get
        {
            if (_authenticationResult.auth == "1")
                return ResultType.Success;
            if (_authenticationResult.auth == "0")
                return ResultType.FailAccountExpired;
            if (_authenticationResult.auth == "-1")
                return ResultType.FailWrongUsernameOrPassword;
            if (_authenticationResult.auth == "-2")
                return ResultType.Banned;


            return ResultType.NoAuthDone;
        }
    }

public enum ResultType { Success, FailWrongUsernameOrPassword, FailAccountExpired, NoAuthDone, Banned }

lo que sucedió fue que _authenticationResult fue nulo una vez, y la propiedad AuthResult arrojó un nullref al intentar "null.auth". ¿Cómo puedo asegurarme (quizás dentro del método CheckUser ()) de que nunca devuelve un valor nulo?

Cuando depuré la aplicación, nunca sucedió. Pero en producción, cuando el servidor agotaba el tiempo de espera, a veces el método devolvía un valor nulo.

Gracias,

preguntado el 08 de noviembre de 11 a las 14:11

Ese código en realidad no funcionaría; siempre debe devolver algo de get AFAIK ... ¿qué debería suceder en el modo de liberación cuando instance1 is null ? -

gracias, esto es solo un pseudocódigo. Por lo general, escribo estas propiedades también con un segundo retorno, después del bloque if. En el modo de lanzamiento, si la instancia1 es nula, obtengo una excepción nullref. Creo que lo que hago es una mala práctica de codificación y tal vez haya algo más elegante que hacer. -

@unholysampler sí ... mi pregunta no era qué pasa cuando instance1 is null por ejemplo pero que debemos sucederá tal caso? una excepción específica? -

¿Cuál es la diferencia entre depurar y liberar? Normalmente, assert está activado durante la depuración y desactivado en la versión de lanzamiento. -

Mirando el ejemplo de código que publicó, creo que la forma elegante de hacer esto es refactorizar su clase (tal vez dividiéndola en dos clases, u otros enfoques que podamos discutir) para que no haya absolutamente ninguna forma de que la persona que llama llame a AuthResult antes a la línea _authenticationResult = authObj.CheckUser (); ser ejecutado -

6 Respuestas

Creo que necesitas entender como instance1, y posteriormente property1 van a ser instanciados, y solo instanciarlos de tal manera que no puedan ser nulos. Esto generalmente se hace verificando los argumentos en la construcción, por ejemplo:

public instance1(string property1)
{
    if (property1 == null) throw new ArgumentNullException("property1");

    this.property1 = property1;
}

Si crea sus tipos de tal manera que no pueden existir en un estado no válido, se asegura de que su código dependiente no se caiga en null valores.

De lo contrario, necesitaríamos ver un ejemplo más completo de lo que está haciendo para brindarle consejos más concretos.

La otra cosa a considerar es en qué estado puede existir su clase en el que se estado requerido de operación, vs. estado opcional de operación. Siendo eso, que miembros son son requeridos para que su clase funcione, y debe esforzarse por diseñar sus clases de modo que siempre tengan el estado requerido, por ejemplo:

public class Person
{
  public Person(string forename, string surname)
  {
    if (forename == null) throw new ArgumentNullException("forename");
    if (surname == null) throw new ArgumentNullException("surname");

    Forename = forename;
    Surname = surname;
  }

  public string Forename { get; private set; }
  public string Surname { get; private set; }
}

En mi tipo de ejemplo, estoy requiriendo que mi Forename y Surname valor tiene un valor no nulo. Esto se aplica a través de mi constructor ... mi Person type nunca se puede instanciar con valores nulos (aunque, tal vez, los valores vacíos sean igual de malos, por lo que verificar IsNullOrWhiteSpace y lanzando un apropiado ArgumentException es la ruta, pero hagámoslo simple).

Si tuviera que presentar un opcional campo, le permitiría mutar el estado de mi Person ejemplo, por ejemplo, dale un setter:

public class Person
{
  public Person(string forename, string surname)
  {
    if (forename == null) throw new ArgumentNullException("forename");
    if (surname == null) throw new ArgumentNullException("surname");

    Forename = forename;
    Surname = surname;
  }

  public string Forename { get; private set; }
  public string Surname { get; private set; }

  public string Initial { get; set; }
}

My Person type aún aplica los campos obligatorios para la operación, pero introduce un campo opcional. Luego debo tener esto en cuenta al realizar una operación que utiliza estos miembros:

public override ToString()
{
  return Forename + (Initial == null ? String.Empty : " " + Initial) + " " + Surname;
}

(Aunque ese no es el mejor ejemplo de una ToString).

respondido 08 nov., 11:19

Este es un muy buen consejo, lo recordaré en el futuro. También he actualizado la publicación inicial con un ejemplo específico según su solicitud. gracias - Amc_rtty

Siento que verificar si una cadena es nula es una especie de tontería. Si inicializa todas las cadenas para que sean una cadena vacía, no tiene que preocuparse por un valor nulo, y siempre hay IsNullOrEmpty. - Sabueso de seguridad

@Ramhound Este puede ser el caso a veces, pero hay podría ser una situación en la que debería haber una diferencia entre algo null vs Empty versus tener un valor. Dependería de cómo espera que los consumidores de su tipo se comporten con esos diferentes valores. - Matthew Abbott

Puedes usar:

if ( instance1 != null && instance1.property1.Equals("bla")){
   // Your code 
 } 

respondido 08 nov., 11:18

Gracias por tu respuesta, lo sé, lo hago todo el tiempo. Estaba buscando algo así como una buena práctica de codificación, alguna respuesta en la línea de pruebas unitarias o algo similar. - Amc_rtty

Su solución es útil, pero aún no es lo que estaba buscando. Pero fui ambiguo en mi publicación inicial: verificar si el objeto es nulo, es tratar el efecto, no la causa, necesito tratar la causa en sí, para nunca permitir que el objeto sea nulo en primer lugar. - Amc_rtty

Entonces es su responsabilidad inicializar la instancia1 correctamente. - Upul Bandara

@Andrei Cristof - Verificar si un objeto es nulo antes de intentar usar una referencia a él no es "tratar el efecto" como lo dice. Incluso reconoces que lo que haces no es la forma "correcta" de hacerlo. - Sabueso de seguridad

Personalmente, usaría el ?? operador (asumiendo property1 es una cuerda)

public string MyString
{
    get { instance1.property1 ?? "Default value"; }
}

respondido 08 nov., 11:18

Las personas generalmente manejan esta situación de tres maneras. La peor forma (en mi opinión) es ser paranoico acerca de cada referencia que miras, siempre probándola con un valor nulo y luego haciendo "" algo "" si encuentras un valor nulo. El problema con este enfoque es que a menudo se encuentra en lo más profundo de algún árbol de llamadas, por lo que el "algo" que hace (como devolver un valor predeterminado "" "razonable" "") no solo es probable que sea una infracción de capas, pero también es probable que disimule un problema en lugar de hacer que se enfrente. En estos casos, probablemente sea mejor dejar que se lance una NulLReferenceException en lugar de hacer un intento a medias para continuar.

Lo más sensato es establecer una convención de codificación en la que sus referencias nunca sean nulas, excepto en unos pocos casos en los que es obvio por el contexto que pueden ser nulas. Además, y siempre que sea posible, uno puede hacer que las clases sean inmutables o casi inmutables para que todas las invariantes se puedan hacer en el constructor y el resto del código pueda continuar con su vida. Por ejemplo, podría escribir:

public class Person {
  private readonly string firstName;
  private readonly string lastName;
  private readonly Nubbin optionalNubbin;
}

... donde está claro por el nombre que OptionalNubbin podría ser nulo.

El enfoque final y más radical es escribir código que no admita un valor nulo. Podrías inventar el dual de Nullable , a saber:

public struct NonNullable<T> {
  ...
}

La implementación podría funcionar de diferentes maneras (ya sea usando una propiedad Value explícita o quizás usando la sobrecarga del operador) pero, en cualquier caso, el trabajo de NonNullable es nunca permitir que alguien lo establezca en nulo.

respondido 08 nov., 11:19

Como instance1.property1 nunca debe ser nulo, vea si hay una manera de inicializarlo correctamente, luego arroje un ArgumentNullException si alguien intenta ponerlo en nulo.

Ejemplo:

public string Property1
{
    set 
    {
      if(value == null)
      {
        throw new ArgumentNullException();
      } 
      instance1.property1 = value;
    }
}

respondido 08 nov., 11:20

puedes hacer algo como a continuación.

public string MyString
{
    get
    {
        if(instance!=null && instance1.property1.Equals("bla"))
        {
            return "bla"; 
        }
        else 
        {
            return String.Empty; 
        }
    }
}

Básicamente, esto comprobará primero si la instancia es nula o no.

respondido 12 nov., 11:20

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.