¿Qué es una excepción NullReferenceException y cómo la soluciono?

1875

Tengo un código y cuando se ejecuta, arroja un NullReferenceException, diciendo:

Referencia a objeto no establecida como instancia de un objeto.

¿Qué significa esto y qué puedo hacer para corregir este error?

John Saunders
fuente
El ayudante de excepción en VS 2017 será más útil para diagnosticar la causa de esta excepción: blogs.msdn.microsoft.com/visualstudio/2016/11/28/… en Ayuda de nueva excepción .
Zev Spitz
Estimados visitantes futuros, las respuestas a esta pregunta se aplican igualmente a una excepción ArgumentNullException . Si su pregunta se ha cerrado como un duplicado de esta y está experimentando un ANE, siga las instrucciones en las respuestas para depurar y solucionar su problema.
@ ANE solo debería suceder si se pasa un valor nulo como parámetro. ¿Puede dar un ejemplo si una pregunta ANE se cierra como un duplicado de esta?
John Saunders
Surgió en Meta, pero tendría que ir a buscar el enlace. Pero en cuanto a ese comentario, un ANE es simplemente un NRE, pero alguien agregó una verificación preventiva, y al menos sabe exactamente qué es nulo (se proporciona el nombre del argumento), por lo que es un poco más fácil de diagnosticar que un NRE directo.

Respuestas:

2416

¿Cual es la causa?

Línea de fondo

Está intentando usar algo que es null(o Nothingen VB.NET). Esto significa que lo configuró nullo nunca lo configuró para nada.

Como cualquier otra cosa, nullse pasa. Si es null en el método "A", podría ser que el método "B" pasó una null de método "A".

null puede tener diferentes significados:

    1. Variables de objeto que no están inicializadas y, por lo tanto, no apuntan a nada. En este caso, si accede a las propiedades o métodos de dichos objetos, provoca a NullReferenceException.
    1. El desarrollador está utilizando nullintencionalmente para indicar que no hay un valor significativo disponible. Tenga en cuenta que C # tiene el concepto de tipos de datos anulables para variables (como las tablas de la base de datos pueden tener campos anulables); puede asignarlos nullpara indicar que no hay ningún valor almacenado en él, por ejemplo, int? a = null;donde el signo de interrogación indica que está permitido almacenar nulo en variable a. Puede verificar eso con if (a.HasValue) {...}o con if (a==null) {...}. Las variables anulables, como aeste ejemplo, permiten acceder al valor a través de forma a.Valueexplícita, o de manera normal a través de a.
      Tenga en cuenta que acceder a él a través de a.Valuearroja un en InvalidOperationExceptionlugar de un NullReferenceExceptionif aesnull- debe hacer la verificación de antemano, es decir, si tiene otra variable anulable int b;, debe hacer asignaciones como if (a.HasValue) { b = a.Value; }o más cortas if (a != null) { b = a; }.

El resto de este artículo entra en más detalles y muestra errores que muchos programadores a menudo cometen y que pueden conducir a una NullReferenceException.

Más específicamente

La runtimelanzar una NullReferenceException siempre significa lo mismo: usted está tratando de utilizar una referencia, y la referencia no se ha inicializado (o fue una vez inicializado, sino que está ya no inicializado).

Esto significa que la referencia es null, y no puede acceder a los miembros (como los métodos) a través de una nullreferencia. El caso más simple:

string foo = null;
foo.ToUpper();

Esto arrojará un NullReferenceExceptionen la segunda línea porque no puede llamar al método de instancia ToUpper()en una stringreferencia que apunta null.

Depuración

¿Cómo encuentras la fuente de un NullReferenceException? Además de mirar la excepción en sí, que se lanzará exactamente en el lugar donde ocurre, se aplican las reglas generales de depuración en Visual Studio: coloque puntos de interrupción estratégicos e inspeccione sus variables , ya sea colocando el mouse sobre sus nombres, abriendo un ( Rápido) Mire la ventana o use los diversos paneles de depuración como Locales y Autos.

Si desea averiguar dónde se establece o no la referencia, haga clic con el botón derecho en su nombre y seleccione "Buscar todas las referencias". Luego puede colocar un punto de interrupción en cada ubicación encontrada y ejecutar su programa con el depurador adjunto. Cada vez que el depurador se interrumpe en dicho punto de interrupción, debe determinar si espera que la referencia no sea nula, inspeccionar la variable y verificar que apunta a una instancia cuando lo espera.

Siguiendo el flujo del programa de esta manera, puede encontrar la ubicación donde la instancia no debe ser nula y por qué no está configurada correctamente.

Ejemplos

Algunos escenarios comunes donde se puede lanzar la excepción:

Genérico

ref1.ref2.ref3.member

Si ref1 o ref2 o ref3 es nulo, obtendrá un NullReferenceException. Si desea resolver el problema, descubra cuál es nulo reescribiendo la expresión a su equivalente más simple:

var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member

Específicamente, en HttpContext.Current.User.Identity.Name, HttpContext.Currentpodría ser nulo, o la Userpropiedad podría ser nula, o la Identitypropiedad podría ser nula.

Indirecto

public class Person 
{
    public int Age { get; set; }
}
public class Book 
{
    public Person Author { get; set; }
}
public class Example 
{
    public void Foo() 
    {
        Book b1 = new Book();
        int authorAge = b1.Author.Age; // You never initialized the Author property.
                                       // there is no Person to get an Age from.
    }
}

Si desea evitar la referencia nula secundaria (Persona), puede inicializarla en el constructor del objeto primario (Libro).

Inicializadores de objetos anidados

Lo mismo se aplica a los inicializadores de objetos anidados:

Book b1 = new Book 
{ 
   Author = { Age = 45 } 
};

Esto se traduce en

Book b1 = new Book();
b1.Author.Age = 45;

Mientras newse usa la palabra clave, solo crea una nueva instancia de Book, pero no una nueva instancia de Person, por lo que Authorla propiedad sigue siendo null.

Inicializadores de colecciones anidadas

public class Person 
{
    public ICollection<Book> Books { get; set; }
}
public class Book 
{
    public string Title { get; set; }
}

La colección anidada se Initializerscomporta igual:

Person p1 = new Person 
{
    Books = {
         new Book { Title = "Title1" },
         new Book { Title = "Title2" },
    }
};

Esto se traduce en

Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });

El new Personúnico crea una instancia de Person, pero la Bookscolección sigue siendo null. La Initializersintaxis de la colección no crea una colección p1.Books, solo se traduce en las p1.Books.Add(...)declaraciones.

Formación

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

Elementos de matriz

Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
                   // initialized. There is no Person to set the Age for.

Matrices Dentadas

long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
                 // Use array[0] = new long[2]; first.

Colección / Lista / Diccionario

Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
                               // There is no Dictionary to perform the lookup.

Rango Variable (indirecto / diferido)

public class Person 
{
    public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
                                  // on the line above.  "p" is null because the
                                  // first element we added to the list is null.

Eventos

public class Demo
{
    public event EventHandler StateChanged;

    protected virtual void OnStateChanged(EventArgs e)
    {        
        StateChanged(this, e); // Exception is thrown here 
                               // if no event handlers have been attached
                               // to StateChanged event
    }
}

###Bad Naming Conventions:

If you named fields differently from locals, you might have realized that you never initialized the field. 

public class Form1 {cliente de cliente privado;

private void Form1_Load(object sender, EventArgs e) 
{
    Customer customer = new Customer();
    customer.Name = "John";
}

private void Button_Click(object sender, EventArgs e)
{
    MessageBox.Show(customer.Name);
}

}

Esto se puede resolver siguiendo la convención para prefijar campos con un guión bajo:

    private Customer _customer;

Ciclo de vida de la página ASP.NET:

public partial class Issues_Edit : System.Web.UI.Page
{
    protected TestIssue myIssue;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
             // Only called on first load, not when button clicked
             myIssue = new TestIssue(); 
        }
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        myIssue.Entry = "NullReferenceException here!";
    }
}

Valores de sesión ASP.NET

// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();

Modelos de vista vacía ASP.NET MVC

Si la excepción ocurre cuando se hace referencia a una propiedad de @Modelen un ASP.NET MVC View, debe comprender que Modelse establece en su método de acción, cuando returnve. Cuando devuelve un modelo vacío (o propiedad de modelo) desde su controlador, la excepción ocurre cuando las vistas acceden a él:

// Controller
public class Restaurant:Controller
{
    public ActionResult Search()
    {
        return View();  // Forgot the provide a Model here.
    }
}

// Razor view 
@foreach (var restaurantSearch in Model.RestaurantSearch)  // Throws.
{
}

<p>@Model.somePropertyName</p> <!-- Also throws -->

Orden de creación de control de WPF y eventos

WPFLos controles se crean durante la llamada a InitializeComponenten el orden en que aparecen en el árbol visual. A se NullReferenceExceptiongenerará en el caso de controles creados con controladores de eventos, etc., que se activan durante los InitializeComponentcuales se hace referencia a los controles creados tarde.

Por ejemplo :

<Grid>
    <!-- Combobox declared first -->
    <ComboBox Name="comboBox1" 
              Margin="10"
              SelectedIndex="0" 
              SelectionChanged="comboBox1_SelectionChanged">
       <ComboBoxItem Content="Item 1" />
       <ComboBoxItem Content="Item 2" />
       <ComboBoxItem Content="Item 3" />
    </ComboBox>

    <!-- Label declared later -->
    <Label Name="label1" 
           Content="Label"
           Margin="10" />
</Grid>

Aquí comboBox1se crea antes label1. Si comboBox1_SelectionChangedintenta hacer referencia a `label1, aún no se habrá creado.

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}

Cambiar el orden de las declaraciones en el XAML(es decir, enumerar label1antes comboBox1, ignorar los problemas de la filosofía del diseño, al menos resolvería NullReferenceExceptionaquí).

Fundido con as

var myThing = someObject as Thing;

Esto no arroja un InvalidCastExceptionpero devuelve un nullcuando falla el lanzamiento (y cuando someObjectes nulo). Así que ten cuidado con eso.

LINQ FirstOrDefault()ySingleOrDefault()

Las versiones simples First()y Single()lanzan excepciones cuando no hay nada. Las versiones "OrDefault" devuelven nulo en ese caso. Así que ten cuidado con eso.

para cada

foreacharroja cuando intenta iterar colección nula. Generalmente causado por un nullresultado inesperado de métodos que devuelven colecciones.

List<int> list = null;    
foreach(var v in list) { } // exception

Ejemplo más realista: seleccione nodos del documento XML. Se lanzará si no se encuentran nodos, pero la depuración inicial muestra que todas las propiedades son válidas:

foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

Formas de evitar

Verifique explícitamente nulle ignore los valores nulos.

Si espera que la referencia a veces sea nula, puede verificarla nullantes de acceder a los miembros de la instancia:

void PrintName(Person p)
{
    if (p != null) 
    {
        Console.WriteLine(p.Name);
    }
}

Verifique explícitamente nully proporcione un valor predeterminado.

Los métodos de llamada que espera devolver pueden devolver una instancia null, por ejemplo, cuando no se puede encontrar el objeto que se busca. Puede elegir devolver un valor predeterminado cuando este sea el caso:

string GetCategory(Book b) 
{
    if (b == null)
        return "Unknown";
    return b.Category;
}

Verifique explícitamente las nullllamadas de método y arroje una excepción personalizada.

También puede lanzar una excepción personalizada, solo para atraparla en el código de llamada:

string GetCategory(string bookTitle) 
{
    var book = library.FindBook(bookTitle);  // This may return null
    if (book == null)
        throw new BookNotFoundException(bookTitle);  // Your custom exception
    return book.Category;
}

Use Debug.Assertsi un valor nunca debería ser null, para detectar el problema antes de que ocurra la excepción.

Cuando sabe durante el desarrollo que un método puede, pero nunca debería regresar null, puede usarlo Debug.Assert()para interrumpirlo tan pronto como sea posible:

string GetTitle(int knownBookID) 
{
    // You know this should never return null.
    var book = library.GetBook(knownBookID);  

    // Exception will occur on the next line instead of at the end of this method.
    Debug.Assert(book != null, "Library didn't return a book for known book ID.");

    // Some other code

    return book.Title; // Will never throw NullReferenceException in Debug mode.
}

Aunque esta verificación no terminará en su versión de lanzamiento , lo que provocará que se lance NullReferenceExceptionnuevamente book == nullen tiempo de ejecución en modo de lanzamiento.

Use GetValueOrDefault()para los nullabletipos de valor para proporcionar un valor predeterminado cuando lo sean null.

DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.

appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default

Utilice el operador de fusión nulo: ??[C #] o If()[VB].

La abreviatura para proporcionar un valor predeterminado cuando nullse encuentra un:

IService CreateService(ILogger log, Int32? frobPowerLevel)
{
   var serviceImpl = new MyService(log ?? NullLog.Instance);

   // Note that the above "GetValueOrDefault()" can also be rewritten to use
   // the coalesce operator:
   serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}

Utilice el operador de condición nula: ?.o ?[x]para matrices (disponible en C # 6 y VB.NET 14):

Esto a veces también se llama el operador de navegación segura o Elvis (después de su forma). Si la expresión en el lado izquierdo del operador es nula, entonces no se evaluará el lado derecho, y en su lugar se devolverá nulo. Eso significa casos como este:

var title = person.Title.ToUpper();

Si la persona no tiene un título, esto generará una excepción porque está intentando invocar ToUpperuna propiedad con un valor nulo.

A C# 5continuación, esto se puede proteger con:

var title = person.Title == null ? null : person.Title.ToUpper();

Ahora la variable de título será nula en lugar de lanzar una excepción. C # 6 introduce una sintaxis más corta para esto:

var title = person.Title?.ToUpper();

Esto dará como resultado la variable de título null, y la llamada a ToUpperno se realiza si person.Titlees así null.

Por supuesto, aún tiene que verificar titlesi es nulo o utilizar el operador de condición nula junto con el operador de fusión nulo ( ??) para proporcionar un valor predeterminado:

// regular null check
int titleLength = 0;
if (title != null)
    titleLength = title.Length; // If title is null, this would throw NullReferenceException

// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;

Del mismo modo, para las matrices puede usar ?[i]lo siguiente:

int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");

Esto hará lo siguiente: Si myIntArrayes nulo, la expresión devuelve nulo y puede verificarlo con seguridad. Si contiene una matriz, hará lo mismo que: elem = myIntArray[i];y devuelve el i<sup>th</sup>elemento.

Usar contexto nulo (disponible en C # 8):

Introducido en el C# 8contexto nulo y los tipos de referencia anulables realizan un análisis estático de las variables y proporciona una advertencia del compilador si un valor puede ser potencialmente nulo o si se ha establecido en nulo. Los tipos de referencia anulables permiten que los tipos sean explícitamente nulos.

El contexto de anulación anulable y el contexto de advertencia anulable se pueden configurar para un proyecto utilizando el Nullableelemento en su csprojarchivo. Este elemento configura cómo el compilador interpreta la nulabilidad de los tipos y qué advertencias se generan. Las configuraciones válidas son:

  • enable: el contexto de anulación anulable está habilitado. El contexto de advertencia anulable está habilitado. Las variables de un tipo de referencia, cadena por ejemplo, no son anulables. Todas las advertencias de nulabilidad están habilitadas.
  • deshabilitar: el contexto de anulación anulable está deshabilitado. El contexto de advertencia anulable está deshabilitado. Las variables de un tipo de referencia son ajenas, al igual que las versiones anteriores de C #. Todas las advertencias de nulabilidad están deshabilitadas.
  • safeonly: el contexto de anotación anulable está habilitado. El contexto de advertencia anulable es seguro. Las variables de un tipo de referencia no son anulables. Todas las advertencias de nulabilidad de seguridad están habilitadas.
  • advertencias: el contexto de anotaciones anulables está deshabilitado. El contexto de advertencia anulable está habilitado. Las variables de un tipo de referencia son ajenas. Todas las advertencias de nulabilidad están habilitadas.
  • safeonlywarnings: el contexto de anulación anulable está deshabilitado. El contexto de advertencia anulable es seguro. Las variables de un tipo de referencia son ajenas. Todas las advertencias de nulabilidad de seguridad están habilitadas.

Se observa un tipo de referencia anulable utilizando la misma sintaxis que los tipos de valores anulables: a ?se agrega al tipo de la variable.

Técnicas especiales para depurar y corregir derefs nulos en iteradores

C#admite "bloques iteradores" (llamados "generadores" en algunos otros idiomas populares). Las excepciones de anulación de referencia pueden ser particularmente difíciles de depurar en bloques iteradores debido a la ejecución diferida:

public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
    for (int i = 0; i < count; ++i)
    yield return f.MakeFrob();
}
...
FrobFactory factory = whatever;
IEnumerable<Frobs> frobs = GetFrobs();
...
foreach(Frob frob in frobs) { ... }

Si whatevercomo resultado nullentonces MakeFroba tirar. Ahora, puede pensar que lo correcto es esto:

// DON'T DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   if (f == null) 
      throw new ArgumentNullException("f", "factory must not be null");
   for (int i = 0; i < count; ++i)
      yield return f.MakeFrob();
}

¿Por qué está mal esto? ¡Porque el bloque iterador no se ejecuta realmente hasta que foreach! La llamada a GetFrobssimplemente devuelve un objeto que cuando se itera ejecutará el bloque iterador.

Al escribir una verificación nula como esta, evita la desreferencia nula, pero mueve la excepción de argumento nulo al punto de la iteración , no al punto de la llamada , y eso es muy confuso para depurar .

La solución correcta es:

// DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   // No yields in a public method that throws!
   if (f == null) 
       throw new ArgumentNullException("f", "factory must not be null");
   return GetFrobsForReal(f, count);
}
private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
{
   // Yields in a private method
   Debug.Assert(f != null);
   for (int i = 0; i < count; ++i)
        yield return f.MakeFrob();
}

Es decir, cree un método auxiliar privado que tenga la lógica de bloqueo del iterador y un método de superficie pública que haga la comprobación nula y devuelva el iterador. Ahora, cuando GetFrobsse llama, la verificación nula ocurre de inmediato y luego se GetFrobsForRealejecuta cuando la secuencia se repite.

Si examina la fuente de referencia para LINQObjetos, verá que esta técnica se utiliza en todo momento. Es un poco más torpe escribir, pero hace que la depuración de errores de nulidad sea mucho más fácil. Optimice su código para la conveniencia de la persona que llama, no la conveniencia del autor .

Una nota sobre desreferencias nulas en código inseguro

C#tiene un modo "inseguro" que, como su nombre lo indica, es extremadamente peligroso porque no se aplican los mecanismos de seguridad normales que proporcionan seguridad de memoria y de tipo. No debe escribir código inseguro a menos que tenga un conocimiento profundo y profundo de cómo funciona la memoria .

En modo inseguro, debe tener en cuenta dos hechos importantes:

  • desreferenciar un puntero nulo produce la misma excepción que desreferenciar una referencia nula
  • desreferenciar un puntero no nulo no válido puede producir esa excepción en algunas circunstancias

Para entender por qué es así, es útil entender cómo .NET produce excepciones de anulación de referencia en primer lugar. (Estos detalles se aplican a .NET que se ejecuta en Windows; otros sistemas operativos utilizan mecanismos similares).

La memoria está virtualizada en Windows; cada proceso obtiene un espacio de memoria virtual de muchas "páginas" de memoria que son rastreadas por el sistema operativo. Cada página de memoria tiene marcas establecidas que determinan cómo se puede usar: leer, escribir, ejecutar, etc. La página más baja está marcada como "producir un error si alguna vez se usa de alguna manera".

Tanto un puntero nulo como una referencia nula C#se representan internamente como el número cero, por lo que cualquier intento de desreferenciarlo en su almacenamiento de memoria correspondiente hace que el sistema operativo produzca un error. El tiempo de ejecución .NET luego detecta este error y lo convierte en la excepción de anulación de referencia nula.

Es por eso que desreferenciar tanto un puntero nulo como una referencia nula produce la misma excepción.

¿Qué pasa con el segundo punto? Anular la referencia a cualquier puntero no válido que se encuentre en la página más baja de la memoria virtual provoca el mismo error del sistema operativo y, por lo tanto, la misma excepción.

¿Por qué esto tiene sentido? Bueno, supongamos que tenemos una estructura que contiene dos entradas y un puntero no administrado igual a nulo. Si intentamos desreferenciar el segundo int en la estructura, CLRno intentaremos acceder al almacenamiento en la ubicación cero; accederá al almacenamiento en la ubicación cuatro. Pero lógicamente, esta es una anulación de referencia nula porque estamos llegando a esa dirección a través de la nula.

Si está trabajando con código inseguro y obtiene una excepción de anulación de referencia nula, solo tenga en cuenta que el puntero infractor no necesita ser nulo. Puede ser cualquier ubicación en la página más baja, y se producirá esta excepción.

LopDev
fuente
55
Tal vez este es un comentario tonto, pero ¿no sería la primera y mejor manera de evitar este problema inicializar el objeto? Para mí, si ocurre este error, generalmente es porque olvidé inicializar algo como el elemento de matriz. Creo que es mucho menos común definir el objeto como nulo y luego hacer referencia a él. Tal vez dé la manera de resolver cada problema adyacente a la descripción. Sigue siendo una buena publicación.
JPK
30
¿Qué pasa si no hay ningún objeto, sino el valor de retorno de un método o propiedad?
John Saunders
66
El ejemplo del libro / autor es un poco raro ... ¿Cómo se compila eso? ¿Cómo funciona incluso el intellisense? ¿Qué es esto? No soy bueno con la computadora ...
55
@ Will: ¿ayuda mi última edición? De lo contrario, sea más explícito sobre lo que ve como un problema.
John Saunders
66
@ JohnSaunders Oh, no, lo siento, me refería a la versión inicializadora del objeto. new Book { Author = { Age = 45 } };¿Cómo funciona la inicialización interna incluso ... No puedo pensar en una situación en la que el init interno funcione alguna vez, sin embargo, compila e intellisense funciona ... A menos que sea para estructuras?
311

Excepción de referencia nula - Visual Basic

El NullReference Exceptionpara Visual Basic no es diferente del de C # . Después de todo, ambos informan la misma excepción definida en .NET Framework que ambos usan. Las causas exclusivas de Visual Basic son raras (quizás solo una).

Esta respuesta usará términos, sintaxis y contexto de Visual Basic. Los ejemplos utilizados provienen de una gran cantidad de preguntas anteriores de Stack Overflow. Esto es para maximizar la relevancia mediante el uso de los tipos de situaciones que a menudo se ven en las publicaciones. También se proporciona un poco más de explicación para aquellos que lo necesiten. Un ejemplo similar al suyo es muy probable que aparezca aquí.

Nota:

  1. Esto está basado en el concepto: no hay código para pegar en su proyecto. Su objetivo es ayudarlo a comprender qué causa una NullReferenceException(NRE), cómo encontrarla, cómo solucionarla y cómo evitarla. Una NRE puede ser causada de muchas maneras, por lo que es poco probable que sea su único encuentro.
  2. Los ejemplos (de las publicaciones de Stack Overflow) no siempre muestran la mejor manera de hacer algo en primer lugar.
  3. Por lo general, se usa el remedio más simple.

Significado Básico

El mensaje "Objeto no establecido en una instancia de Object" significa que está intentando utilizar un objeto que no se ha inicializado. Esto se reduce a uno de estos:

  • Su código declaró una variable de objeto, pero no la inicializó (cree una instancia o ' instanciarla ')
  • Algo que su código asumió que inicializaría un objeto, no
  • Posiblemente, otro código invalida prematuramente un objeto que todavía está en uso

Encontrar la causa

Dado que el problema es una referencia a un objeto Nothing, la respuesta es examinarlos para averiguar cuál. Luego determine por qué no se inicializa. Mantenga el mouse sobre las diversas variables y Visual Studio (VS) mostrará sus valores, el culpable será Nothing.

Pantalla de depuración IDE

También debe eliminar los bloques Try / Catch del código relevante, especialmente aquellos en los que no hay nada en el bloque Catch. Esto hará que su código se bloquee cuando intente usar un objeto que es Nothing. Esto es lo que desea porque identificará la ubicación exacta del problema y le permitirá identificar el objeto que lo causó.

A MsgBoxen la captura que muestra Error while...será de poca ayuda. Este método también lleva a preguntas de desbordamiento de pila muy malas , porque no puede describir la excepción real, el objeto involucrado o incluso la línea de código donde sucede.

También puede usar Locals Window( Depurar -> Windows -> Locales ) para examinar sus objetos.

Una vez que sepa cuál y dónde está el problema, generalmente es bastante fácil de solucionar y más rápido que publicar una nueva pregunta.

Ver también:

Ejemplos y remedios

Objetos de clase / Crear una instancia

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

El problema es que Dimno crea un objeto CashRegister ; solo declara una variable llamada regde ese tipo. Declarar una variable de objeto y crear una instancia son dos cosas diferentes.

Remedio

El Newoperador a menudo se puede usar para crear la instancia cuando la declaras:

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

Cuando solo es apropiado crear la instancia más tarde:

Private reg As CashRegister         ' Declare
  ...
reg = New CashRegister()            ' Create instance

Nota: No lo use Dimnuevamente en un procedimiento, incluido el constructor ( Sub New):

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

Esto creará una variable localreg , que existe solo en ese contexto (sub). La regvariable con nivel de módulo Scopeque usará en cualquier otro lugar permanece Nothing.

La falta del Newoperador es la causa número 1 de loNullReference Exceptions visto en las preguntas de desbordamiento de pila revisadas.

Visual Basic intenta aclarar el proceso repetidamente utilizando New: El uso del Newoperador crea un nuevo objeto y llama Sub Newal constructor, donde su objeto puede realizar cualquier otra inicialización.

Para ser claros, Dim(o Private) solo declara una variable y su Type. El alcance de la variable, ya sea que exista para todo el módulo / clase o sea local para un procedimiento, se determina por el lugar donde se declara. Private | Friend | Publicdefine el nivel de acceso, no el alcance .

Para más información, ver:


Matrices

Las matrices también deben ser instanciadas:

Private arr as String()

Esta matriz solo ha sido declarada, no creada. Hay varias formas de inicializar una matriz:

Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}

' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}

Nota: a partir de VS 2010, al inicializar una matriz local utilizando un literal y Option Infer, los elementos As <Type>y Newson opcionales:

Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}

El tipo de datos y el tamaño de la matriz se infieren de los datos que se asignan. Las declaraciones de nivel de clase / módulo aún requieren As <Type>con Option Strict:

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

Ejemplo: matriz de objetos de clase

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

La matriz se ha creado, pero los Fooobjetos que contiene no.

Remedio

For i As Integer = 0 To arrFoo.Count - 1
    arrFoo(i) = New Foo()         ' Create Foo instance
    arrFoo(i).Bar = i * 10
Next

Usar a List(Of T)hará que sea bastante difícil tener un elemento sin un objeto válido:

Dim FooList As New List(Of Foo)     ' List created, but it is empty
Dim f As Foo                        ' Temporary variable for the loop

For i As Integer = 0 To 5
    f = New Foo()                    ' Foo instance created
    f.Bar =  i * 10
    FooList.Add(f)                   ' Foo object added to list
Next

Para más información, ver:


Listas y Colecciones

Las colecciones .NET (de las cuales hay muchas variedades - Listas, Diccionario, etc.) también deben ser instanciadas o creadas.

Private myList As List(Of String)
..
myList.Add("ziggy")           ' NullReference

Obtiene la misma excepción por el mismo motivo: myListsolo se declaró, pero no se creó ninguna instancia. El remedio es el mismo:

myList = New List(Of String)

' Or create an instance when declared:
Private myList As New List(Of String)

Un descuido común es una clase que usa una colección Type:

Public Class Foo
    Private barList As List(Of Bar)

    Friend Function BarCount As Integer
        Return barList.Count
    End Function

    Friend Sub AddItem(newBar As Bar)
        If barList.Contains(newBar) = False Then
            barList.Add(newBar)
        End If
    End Function

Cualquiera de los procedimientos dará como resultado una NRE, porque barListsolo se declara, no se instancia. Crear una instancia de Foono también creará una instancia de lo interno barList. Puede haber sido la intención de hacer esto en el constructor:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

Como antes, esto es incorrecto:

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

Para más información, ver List(Of T)Clase .


Objetos de proveedor de datos

Trabajar con bases de datos presenta muchas oportunidades para un NullReference porque no puede haber muchos objetos ( Command, Connection, Transaction, Dataset, DataTable, DataRows....) en el uso de una sola vez. Nota: No importa qué proveedor de datos esté utilizando (MySQL, SQL Server, OleDB, etc.), los conceptos son los mismos.

Ejemplo 1

Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer

con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()

MaxRows = ds.Tables("foobar").Rows.Count      ' Error

Como antes, dsse declaró el objeto Dataset, pero nunca se creó una instancia. El DataAdapterllenará un existente DataSet, no creará uno. En este caso, dado que dses una variable local, el IDE le advierte que esto podría suceder:

img

Cuando se declara como una variable de nivel de módulo / clase, como parece ser el caso con, el compilador no puede saber si el objeto fue creado por un procedimiento ascendente. No ignore las advertencias.

Remedio

Dim ds As New DataSet

Ejemplo 2

ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")

txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)

Un error tipográfico es un problema aquí: Employeesvs Employee. No se DataTablecreó un nombre de "Empleado", por lo que los NullReferenceExceptionresultados intentaron acceder a él. Otro problema potencial es asumir que habrá lo Itemsque puede no ser así cuando el SQL incluye una cláusula WHERE.

Remedio

Como esto usa una tabla, el uso Tables(0)evitará errores ortográficos. El examen Rows.Counttambién puede ayudar:

If ds.Tables(0).Rows.Count > 0 Then
    txtID.Text = ds.Tables(0).Rows(0).Item(1)
    txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If

Filles una función que devuelve el número de Rowsafectados que también se puede probar:

If da.Fill(ds, "Employees") > 0 Then...

Ejemplo 3

Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
        TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
        FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)

If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then

La DataAdapterproporcionará TableNamescomo se muestra en el ejemplo anterior, pero no es así nombres de análisis sintáctico de la tabla o base de datos SQL. Como resultado, hace ds.Tables("TICKET_RESERVATION")referencia a una tabla inexistente.

El remedio es el mismo, consulte la tabla por índice:

If ds.Tables(0).Rows.Count > 0 Then

Ver también la clase DataTable .


Rutas de objeto / anidadas

If myFoo.Bar.Items IsNot Nothing Then
   ...

El código solo está probando Itemsmientras ambos myFooy Bartambién puede ser Nothing. El remedio es probar la cadena o ruta completa de los objetos, uno a la vez:

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

AndAlsoes importante. Las pruebas posteriores no se realizarán una vez Falseque se encuentre la primera condición. Esto permite que el código 'se desplace' de forma segura en el (los) objeto (s) un 'nivel' a la vez, evaluando myFoo.Barsolo después de (y si) myFoose determina que es válido. Las cadenas o rutas de objetos pueden ser bastante largas al codificar objetos complejos:

myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")

No es posible hacer referencia a nada 'aguas abajo' de un nullobjeto. Esto también se aplica a los controles:

myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"

Aquí, myWebBrowsero Documentpodría ser Nada o el formfld1elemento puede no existir.


Controles de UI

Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
     & "FROM Invoice where invoice_no = '" & _
     Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
     Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
     Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
     Me.expiry.Text & "'", con)

Entre otras cosas, este código no anticipa que el usuario no haya seleccionado algo en uno o más controles de IU. ListBox1.SelectedItembien puede ser Nothing, por ListBox1.SelectedItem.ToStringlo que resultará en una NRE.

Remedio

Valide los datos antes de usarlos (también use Option Stricty parámetros SQL):

Dim expiry As DateTime         ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
    (ListBox1.SelectedItems.Count > 0) AndAlso
    (ComboBox2.SelectedItems.Count > 0) AndAlso
    (DateTime.TryParse(expiry.Text, expiry) Then

    '... do stuff
Else
    MessageBox.Show(...error message...)
End If

Alternativamente, puedes usar (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Formas de Visual Basic

Public Class Form1

    Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
                   Controls("TextBox2"), Controls("TextBox3"), _
                   Controls("TextBox4"), Controls("TextBox5"), _
                   Controls("TextBox6")}

    ' same thing in a different format:
    Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}

    ' Immediate NRE:
    Private somevar As String = Me.Controls("TextBox1").Text

Esta es una forma bastante común de obtener una NRE. En C #, dependiendo de cómo esté codificado, el IDE informará que Controlsno existe en el contexto actual o que "no puede hacer referencia a un miembro no estático". Entonces, hasta cierto punto, esta es una situación de solo VB. También es complejo porque puede provocar una cascada de fallas.

Las matrices y colecciones no se pueden inicializar de esta manera. Este código de inicialización se ejecutará antes de que el constructor cree el Formo el Controls. Como resultado:

  • Las listas y la colección simplemente estarán vacías
  • The Array contendrá cinco elementos de Nothing
  • La somevarasignación dará como resultado una NRE inmediata porque Nothing no tiene una .Textpropiedad

Hacer referencia a elementos de la matriz más adelante dará como resultado una NRE. Si hace esto Form_Load, debido a un error extraño, el IDE puede no informar la excepción cuando ocurra. La excepción aparecerá más tarde cuando su código intente usar la matriz. Esta "excepción silenciosa" se detalla en esta publicación . Para nuestros propósitos, la clave es que cuando ocurre algo catastrófico al crear un formulario ( Sub Newo Form Loadevento), las excepciones pueden no ser reportadas, el código sale del procedimiento y solo muestra el formulario.

Dado que ningún otro código en tu Sub Newo Form Loadevento se desarrollará después de la NRE, un gran número de otras cosas se pueden dejar sin inicializar.

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

Tenga en cuenta que esto se aplica a todas y cada una de las referencias de control y componentes que las hacen ilegales donde están:

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

Remedio parcial

Es curioso que VB no proporciona una advertencia, pero el remedio es declarar los contenedores en el nivel de la forma, pero inicializar en controlador de eventos de carga de formulario cuando los controles hacen existir. Esto se puede hacer Sub Newsiempre que su código esté después de la InitializeComponentllamada:

' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String

' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text           ' For simple control references

Es posible que el código de matriz aún no esté fuera de peligro. Los controles que están en un control de contenedor (como a GroupBoxo Panel) no se encontrarán en Me.Controls; estarán en la colección de Controles de ese Panel o GroupBox. Tampoco se devolverá un control cuando el nombre del control esté mal escrito ( "TeStBox2"). En tales casos, Nothingse almacenará nuevamente en esos elementos de la matriz y se producirá un NRE cuando intente hacer referencia a él.

Estos deberían ser fáciles de encontrar ahora que sabe lo que está buscando: VS te muestra el error de tus caminos

"Button2" reside en un Panel

Remedio

En lugar de referencias indirectas por nombre usando la Controlscolección del formulario , use la referencia de control:

' Declaration
Private NameBoxes As TextBox()

' Initialization -  simple and easy to read, hard to botch:
NameBoxes = New TextBox() {TextBox1, TextBox2, ...)

' Initialize a List
NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})
' or
NamesList = New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})

Función que no devuelve nada

Private bars As New List(Of Bars)        ' Declared and created

Public Function BarList() As List(Of Bars)
    bars.Clear
    If someCondition Then
        For n As Integer = 0 to someValue
            bars.Add(GetBar(n))
        Next n
    Else
        Exit Function
    End If

    Return bars
End Function

Este es un caso en el que el IDE le advertirá que " no todas las rutas devuelven un valor y NullReferenceExceptionpueden resultar ". Puede suprimir la advertencia, reemplazando Exit Functioncon Return Nothing, pero eso no resuelve el problema. Cualquier cosa que intente usar el retorno cuando someCondition = Falsedará como resultado una NRE:

bList = myFoo.BarList()
For Each b As Bar in bList      ' EXCEPTION
      ...

Remedio

Reemplazar Exit Functionen la función con Return bList. Devolver un vacío List no es lo mismo que devolver Nothing. Si existe la posibilidad de que se pueda devolver un objeto Nothing, pruebe antes de usarlo:

 bList = myFoo.BarList()
 If bList IsNot Nothing Then...

Prueba / captura mal implementada

Un Try / Catch mal implementado puede ocultar dónde está el problema y generar otros nuevos:

Dim dr As SqlDataReader
Try
    Dim lnk As LinkButton = TryCast(sender, LinkButton)
    Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
    Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
    ViewState("username") = eid
    sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
             Pager, mailaddress, from employees1 where username='" & eid & "'"
    If connection.State <> ConnectionState.Open Then
        connection.Open()
    End If
    command = New SqlCommand(sqlQry, connection)

    'More code fooing and barring

    dr = command.ExecuteReader()
    If dr.Read() Then
        lblFirstName.Text = Convert.ToString(dr("FirstName"))
        ...
    End If
    mpe.Show()
Catch

Finally
    command.Dispose()
    dr.Close()             ' <-- NRE
    connection.Close()
End Try

Este es un caso de un objeto que no se crea como se esperaba, pero también demuestra la utilidad del contador de un vacío Catch.

Hay una coma adicional en el SQL (después de 'mailaddress') que da como resultado una excepción en .ExecuteReader. Después de Catchque no hace nada, Finallyintenta realizar la limpieza, pero como no puede Closeun DataReaderobjeto nulo , se NullReferenceExceptionobtienen resultados completamente nuevos .

Un Catchbloque vacío es el patio del diablo. Este OP estaba desconcertado por qué estaba obteniendo una NRE en el Finallybloque. En otras situaciones, un vacío Catchpuede dar lugar a que algo mucho más alejado se vuelva loco y hacer que pase tiempo mirando las cosas incorrectas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).

Remedio

No use bloques vacíos Try / Catch: deje que el código se bloquee para que pueda a) identificar la causa b) identificar la ubicación yc) aplicar un remedio adecuado. Los bloques Try / Catch no están destinados a ocultar excepciones de la persona calificada para solucionarlos: el desarrollador.


DBNull no es lo mismo que Nothing

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

La IsDBNullfunción se usa para probar si un valor es igual a System.DBNull: Desde MSDN:

El valor System.DBNull indica que el Objeto representa datos faltantes o inexistentes. DBNull no es lo mismo que Nothing, lo que indica que una variable aún no se ha inicializado.

Remedio

If row.Cells(0) IsNot Nothing Then ...

Como antes, puede probar para Nada, luego para un valor específico:

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

Ejemplo 2

Dim getFoo = (From f In dbContext.FooBars
               Where f.something = something
               Select f).FirstOrDefault

If Not IsDBNull(getFoo) Then
    If IsDBNull(getFoo.user_id) Then
        txtFirst.Text = getFoo.first_name
    Else
       ...

FirstOrDefaultdevuelve el primer elemento o el valor predeterminado, que es Nothingpara tipos de referencia y nunca DBNull:

If getFoo IsNot Nothing Then...

Control S

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

Si no se puede encontrar un CheckBoxwith chkName(o existe en a GroupBox), entonces chkserá Nothing e intentar hacer referencia a cualquier propiedad dará como resultado una excepción.

Remedio

If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...

El DataGridView

El DGV tiene algunas peculiaridades que se ven periódicamente:

dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True       ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"

Si dgvBookses AutoGenerateColumns = Trueasí, creará las columnas, pero no las nombrará, por lo que el código anterior falla cuando hace referencia a ellas por su nombre.

Remedio

Nombre las columnas manualmente, o haga referencia por índice:

dgvBooks.Columns(0).Visible = True

Ejemplo 2 - Cuidado con el NewRow

xlWorkSheet = xlWorkBook.Sheets("sheet1")

For i = 0 To myDGV.RowCount - 1
    For j = 0 To myDGV.ColumnCount - 1
        For k As Integer = 1 To myDGV.Columns.Count
            xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
            xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
        Next
    Next
Next

Cuando DataGridViewtiene AllowUserToAddRowscomo True(el valor predeterminado), todo Cellsen la fila en blanco / nueva en la parte inferior contendrá Nothing. La mayoría de los intentos de usar el contenido (por ejemplo ToString) dará como resultado una NRE.

Remedio

Use un For/Eachbucle y pruebe la IsNewRowpropiedad para determinar si es esa última fila. Esto funciona si AllowUserToAddRowses cierto o no:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

Si usa un For nbucle, modifique el recuento de filas o use Exit Forcuándo IsNewRowes verdadero.


My.Settings (StringCollection)

Bajo ciertas circunstancias, tratar de usar un elemento del My.Settingscual es un StringCollectionpuede resultar en una NullReference la primera vez que la use. La solución es la misma, pero no tan obvia. Considerar:

My.Settings.FooBars.Add("ziggy")         ' foobars is a string collection

Dado que VB administra la configuración por usted, es razonable esperar que inicialice la recopilación. Lo hará, pero solo si ha agregado previamente una entrada inicial a la colección (en el editor de Configuración). Como la colección se inicializa (aparentemente) cuando se agrega un elemento, permanece Nothingcuando no hay elementos en el editor de Configuración para agregar.

Remedio

Inicialice la colección de configuraciones en el Loadcontrolador de eventos del formulario , si es necesario:

If My.Settings.FooBars Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

Por lo general, la Settingscolección solo deberá inicializarse la primera vez que se ejecute la aplicación. Una solución alternativa es agregar un valor inicial a su colección en Proyecto -> Configuración | FooBars , guarde el proyecto, luego elimine el valor falso.


Puntos clave

Probablemente olvidaste el Newoperador.

o

Algo que asumió que funcionaría perfectamente para devolver un objeto inicializado a su código, no lo hizo.

No ignore las advertencias del compilador (nunca) y use Option Strict On(siempre).


Excepción de referencia nula de MSDN

Plutonix
fuente
226

Otro escenario es cuando convierte un objeto nulo en un tipo de valor . Por ejemplo, el siguiente código:

object o = null;
DateTime d = (DateTime)o;

Lanzará un NullReferenceExceptionsobre el elenco. Parece bastante obvio en el ejemplo anterior, pero esto puede suceder en escenarios intrincados más "de enlace tardío" en los que el objeto nulo ha sido devuelto por algún código que no es de su propiedad, y el reparto es generado, por ejemplo, por algún sistema automático.

Un ejemplo de esto es este fragmento de enlace ASP.NET simple con el control Calendar:

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

Aquí, SelectedDatede hecho , es una propiedad, de DateTimetipo, del Calendartipo Control web, y el enlace podría devolver algo nulo perfectamente. El Generador ASP.NET implícito creará un fragmento de código que será equivalente al código de transmisión anterior. Y esto generará un problema NullReferenceExceptionque es bastante difícil de detectar, ya que se encuentra en el código generado por ASP.NET que se compila bien ...

Simon Mourier
fuente
77
Gran captura Forma única de evitar:DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Serge Shultz
160

Significa que la variable en cuestión no apunta a nada. Podría generar esto así:

SqlConnection connection = null;
connection.Open();

Eso arrojará el error porque aunque he declarado la variable " connection", no apunta a nada. Cuando intento llamar al miembro " Open", no hay ninguna referencia para resolverlo y arrojará el error.

Para evitar este error:

  1. Siempre inicialice sus objetos antes de intentar hacer algo con ellos.
  2. Si no está seguro de si el objeto es nulo, verifíquelo con object == null.

La herramienta Resharper de JetBrains identificará cada lugar en su código que tenga la posibilidad de un error de referencia nulo, lo que le permite realizar una verificación nula. Este error es la fuente número uno de errores, en mi humilde opinión.

Chris B. Behrens
fuente
3
La herramienta Resharper de JetBrains identificará cada lugar en su código que tenga la posibilidad de un error de referencia nulo. Esto es incorrecto. Tengo una solución sin esa detección, pero el código ocasionalmente resulta en la excepción. Sospecho que en ocasiones es indetectable, al menos por ellos, cuando se trata de subprocesos múltiples, pero no puedo comentar más porque todavía no identifiqué la ubicación de mi error.
j riv
Pero cómo resolverlo cuando NullReferenceException viene en usign HttpContext.Current.Responce.Clear (). No se resuelve con ninguna de las soluciones anteriores. porque al crear su objeto objeto de HttpContext aparece un error "La resolución de sobrecarga falló porque ningún 'Nuevo' accesible acepta este Número de argumentos.
Sunny Sandeep
158

Significa que su código utilizó una variable de referencia de objeto que se estableció en nulo (es decir, no hizo referencia a una instancia de objeto real).

Para evitar el error, los objetos que podrían ser nulos deben ser probados para nulo antes de ser utilizados.

if (myvar != null)
{
    // Go ahead and use myvar
    myvar.property = ...
}
else
{
    // Whoops! myvar is null and cannot be used without first
    // assigning it to an instance reference
    // Attempting to use myvar here will result in NullReferenceException
}
Jonathan Wood
fuente
96

Tenga en cuenta que, independientemente del escenario, la causa es siempre la misma en .NET:

Está intentando utilizar una variable de referencia cuyo valor es Nothing/ null. Cuando el valor es Nothing/ nullpara la variable de referencia, eso significa que en realidad no contiene una referencia a una instancia de ningún objeto que exista en el montón.

Nunca asignó algo a la variable, nunca creó una instancia del valor asignado a la variable, o configuró la variable igual Nothing/ nullmanualmente, o llamó a una función que establezca la variable en Nothing/ nullpara usted.

código maestro
fuente
87

Un ejemplo de esta excepción lanzada es: cuando intenta verificar algo, eso es nulo.

Por ejemplo:

string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)

if (testString.Length == 0) // Throws a nullreferenceexception
{
    //Do something
} 

El tiempo de ejecución de .NET generará una NullReferenceException cuando intente realizar una acción en algo que no se haya instanciado, es decir, el código anterior.

En comparación con una excepción ArgumentNullException que generalmente se lanza como una medida defensiva si un método espera que lo que se le pasa no sea nulo.

Más información está en C # NullReferenceException y Null Parameter .

Alex KeySmith
fuente
87

Actualización C # 8.0, 2019: tipos de referencia anulables

C # 8.0 introduce tipos de referencia anulables y tipos de referencia no anulables . Tipos de referencia por lo que sólo admiten nulos deben ser evaluados para evitar una NullReferenceException .


Si no ha inicializado un tipo de referencia y desea establecer o leer una de sus propiedades, arrojará una NullReferenceException .

Ejemplo:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Simplemente puede evitar esto comprobando si la variable no es nula:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Para comprender completamente por qué se produce una NullReferenceException, es importante conocer la diferencia entre los tipos de valor y [tipos de referencia] [3].

Por lo tanto, si se trata de tipos de valores , NullReferenceExceptions no puede ocurrir. ¡Aunque debe mantenerse alerta al tratar con tipos de referencia !

Solo los tipos de referencia, como sugiere el nombre, pueden contener referencias o apuntar literalmente a nada (o 'nulo'). Mientras que los tipos de valor siempre contienen un valor.

Tipos de referencia (estos deben ser verificados):

  • dinámica
  • objeto
  • cuerda

Tipos de valor (simplemente puede ignorar estos):

  • Tipos numéricos
  • Tipos integrales
  • Tipos de punto flotante
  • decimal
  • bool
  • Estructuras definidas por el usuario
Fabian Bigler
fuente
66
-1: dado que la pregunta es "¿Qué es una NullReferenceException", los tipos de valor no son relevantes.
John Saunders,
21
@ John Saunders: No estoy de acuerdo. Como desarrollador de software, es realmente importante poder distinguir entre el valor y los tipos de referencia. de lo contrario, las personas terminarán verificando si los enteros son nulos.
Fabian Bigler
55
Es cierto, simplemente no en el contexto de esta pregunta.
John Saunders
44
Gracias por la pista. Lo mejoré un poco y agregué un ejemplo en la parte superior. Todavía creo que mencionar los tipos de referencia y valor es útil.
Fabian Bigler
55
Creo que no ha agregado nada que no estaba en las otras respuestas, ya que la pregunta supone un tipo de referencia.
John Saunders
78

Otro caso en el que NullReferenceExceptionspuede suceder es el uso (incorrecto) del asoperador :

class Book {
    public string Name { get; set; }
}
class Car { }

Car mycar = new Car();
Book mybook = mycar as Book;   // Incompatible conversion --> mybook = null

Console.WriteLine(mybook.Name);   // NullReferenceException

Aquí, Booky Carson tipos incompatibles; a Carno se puede convertir / lanzar a a Book. Cuando este lanzamiento falla, asregresa null. Usar mybookdespués de esto causa a NullReferenceException.

En general, debe usar un yeso o as, de la siguiente manera:

Si espera que la conversión de tipos siempre tenga éxito (es decir, sabe cuál debe ser el objeto antes de tiempo), entonces debe usar un molde:

ComicBook cb = (ComicBook)specificBook;

Si no está seguro del tipo, pero desea intentar usarlo como un tipo específico, use as:

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}
Jonathon Reinhart
fuente
2
Esto puede suceder mucho al desempaquetar una variable. Encuentro que sucede a menudo en los controladores de eventos después de cambiar el tipo del elemento de la interfaz de usuario, pero olvido actualizar el código subyacente.
Brendan
65

Está utilizando el objeto que contiene la referencia de valor nulo. Entonces está dando una excepción nula. En el ejemplo, el valor de la cadena es nulo y, al verificar su longitud, se produjo la excepción.

Ejemplo:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

El error de excepción es:

Excepción no controlada:

System.NullReferenceException: referencia de objeto no establecida en una instancia de un objeto. en Program.Main ()

usuario1814380
fuente
1
¡Qué profundo! Nunca consideré la constante 'nula' como un valor de referencia. Así es como C # abstrae un "puntero nulo" ¿eh? B / c, como recuerdo en C ++, un NPE puede ser causado al desreferenciar un puntero no inicializado (es decir, tipo de referencia en c #) cuyo valor predeterminado es una dirección que no está asignada a ese proceso (en muchos casos esto sería 0, especialmente en versiones posteriores de C ++ que hicieron la autoinicialización, que pertenece al sistema operativo, con él y mueren (o simplemente detecta el sigkill con el que el sistema operativo ataca su proceso)).
samis
64

Si bien lo que causa un NullReferenceExceptions y los enfoques para evitar / solucionar dicha excepción se han abordado en otras respuestas, lo que muchos programadores aún no han aprendido es cómo depurar de forma independiente dichas excepciones durante el desarrollo.

En Visual Studio, esto suele ser fácil gracias al Visual Studio Debugger .


Primero, asegúrese de detectar el error correcto: consulte ¿Cómo permito romper en 'System.NullReferenceException' en VS2010? Nota 1

Luego, comience con la depuración (F5) o adjunte [el depurador VS] al proceso en ejecución . En ocasiones puede ser útil usar Debugger.Break, lo que le pedirá que inicie el depurador.

Ahora, cuando se lanza la NullReferenceException (o no se controla), el depurador se detendrá (¿recuerda la regla establecida anteriormente?) En la línea en la que ocurrió la excepción. A veces el error será fácil de detectar.

Por ejemplo, en la siguiente línea, el único código que puede causar la excepción es si se myStringevalúa como nulo. Esto se puede verificar mirando la Ventana de Observación o ejecutando expresiones en la Ventana Inmediata .

var x = myString.Trim();

En casos más avanzados, como los siguientes, deberá usar una de las técnicas anteriores (Watch o Windows Inmediato) para inspeccionar las expresiones para determinar si str1era nulo o si str2era nulo.

var x = str1.Trim() + str2.Trim();

Una vez que se ha localizado la excepción, generalmente es trivial razonar hacia atrás para descubrir dónde se introdujo [incorrectamente] el valor nulo:

Tómese el tiempo necesario para comprender la causa de la excepción. Inspeccione las expresiones nulas. Inspeccione las expresiones anteriores que podrían haber resultado en tales expresiones nulas. Agregue puntos de interrupción y avance por el programa según corresponda. Usa el depurador.


1 Si Break on Throws es demasiado agresivo y el depurador se detiene en un NPE en la biblioteca .NET o de terceros, se puede usar Break on User-Unledled para limitar las excepciones detectadas. Además, VS2012 presenta Just My Code, que recomiendo habilitar también.

Si está depurando con Just My Code habilitado, el comportamiento es ligeramente diferente. Con Just My Code habilitado, el depurador ignora las excepciones de Common Language Runtime (CLR) de primera oportunidad que se arrojan fuera de My Code y no pasan por My Code

usuario2864740
fuente
59

Simon Mourier dio este ejemplo :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

donde una conversión de unboxing (cast) de object (o de una de las clases System.ValueTypeo System.Enum, o de un tipo de interfaz) a un tipo de valor (que no seaNullable<> ) en sí mismo proporciona el NullReferenceException.

En la otra dirección, una conversión de boxeo de una Nullable<>que tieneHasValue igual false a un tipo de referencia, puede dar una nullreferencia que luego puede conducir a a NullReferenceException. El ejemplo clásico es:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

A veces el boxeo ocurre de otra manera. Por ejemplo con este método de extensión no genérico:

public static void MyExtension(this object x)
{
  x.ToString();
}

el siguiente código será problemático:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Estos casos surgen debido a las reglas especiales que el tiempo de ejecución usa al boxear Nullable<> instancias.

Jeppe Stig Nielsen
fuente
42

Agregar un caso cuando el nombre de la clase para la entidad utilizada en el marco de la entidad es el mismo que el nombre de la clase para un archivo de código subyacente de formulario web.

Supongamos que tiene un formulario web Contact.aspx cuya clase de código subyacente es Contact y tiene un nombre de entidad Contact.

Luego, el siguiente código arrojará una NullReferenceException cuando llame a context.SaveChanges ()

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

En aras de la integridad de la clase DataContext

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

y clase de entidad de contacto. A veces, las clases de entidad son clases parciales, por lo que también puede ampliarlas en otros archivos.

public partial class Contact 
{
    public string Name {get; set;}
}

El error ocurre cuando la entidad y la clase codebehind están en el mismo espacio de nombres. Para solucionar esto, cambie el nombre de la clase de entidad o la clase de código subyacente para Contact.aspx.

Razón Todavía no estoy seguro del motivo. Pero cada vez que cualquiera de la clase de entidad extenderá System.Web.UI.Page, se produce este error.

Para discusión, eche un vistazo a NullReferenceException en DbContext.saveChanges ()

revs AbhinavRanjan
fuente
41

Otro caso general en el que uno podría recibir esta excepción implica burlarse de las clases durante las pruebas unitarias. Independientemente del marco de simulación que se utilice, debe asegurarse de que todos los niveles apropiados de la jerarquía de clases se burlen correctamente. En particular, todas las propiedades deHttpContext deben burlar que hace referencia el código bajo prueba.

Consulte " NullReferenceException lanzada al probar AuthorizationAttribute personalizado " para obtener un ejemplo algo detallado.

John Saunders
fuente
40

Tengo una perspectiva diferente para responder esto. Este tipo de respuestas "¿qué más puedo hacer para evitarlo? "

Cuando se trabaja en diferentes capas , por ejemplo en una aplicación MVC, un controlador necesita servicios para llamar a las operaciones comerciales. En tales escenarios, el Contenedor de inyección de dependencias se puede utilizar para inicializar los servicios para evitar la NullReferenceException . Eso significa que no necesita preocuparse por verificar nulos y simplemente llamar a los servicios desde el controlador como si siempre estuvieran disponibles (e inicializados) como un singleton o un prototipo.

public class MyController
{
    private ServiceA serviceA;
    private ServiceB serviceB;

    public MyController(ServiceA serviceA, ServiceB serviceB)
    {
        this.serviceA = serviceA;
        this.serviceB = serviceB;
    }

    public void MyMethod()
    {
        // We don't need to check null because the dependency injection container 
        // injects it, provided you took care of bootstrapping it.
        var someObject = serviceA.DoThis();
    }
}
Mukus
fuente
66
-1: esto solo maneja un escenario único: el de las dependencias no inicializadas. Este es un escenario minoritario para NullReferenceException. La mayoría de los casos son simples malentendidos sobre cómo funcionan los objetos. Los siguientes más frecuentes son otras situaciones en las que el desarrollador asumió que el objeto se inicializaría automáticamente.
John Saunders
La inyección de dependencia generalmente no se usa para evitar NullReferenceException. No creo que hayas encontrado un escenario general aquí. En cualquier caso, si edita su respuesta para que sea más al estilo de stackoverflow.com/a/15232518/76337 , eliminaré el voto negativo.
John Saunders
38

En cuanto a "qué debo hacer al respecto" , puede haber muchas respuestas.

Una forma más "formal" de prevenir tales condiciones de error durante el desarrollo es aplicar el diseño por contrato en su código. Esto significa que necesita establecer invariantes de clase , y / o incluso precondiciones y postcondiciones de función / método en su sistema, durante el desarrollo.

En resumen, los invariantes de clase aseguran que habrá algunas restricciones en su clase que no serán violadas en el uso normal (y, por lo tanto, la clase no entrará en un estado inconsistente). Las condiciones previas significan que los datos proporcionados como entrada para una función / método deben seguir algunas restricciones establecidas y nunca violarlas, y las condiciones posteriores significan que una salida de función / método debe seguir las restricciones establecidas nuevamente sin violarlas nunca. Las condiciones del contrato nunca deben violarse durante la ejecución de un programa libre de errores, por lo tanto, el diseño por contrato se verifica en la práctica en modo de depuración, mientras se desactiva en las versiones , para maximizar el rendimiento del sistema desarrollado.

De esta manera, puede evitar NullReferenceExceptioncasos que son el resultado de la violación de las restricciones establecidas. Por ejemplo, si usa una propiedad de objeto Xen una clase y luego intenta invocar uno de sus métodos y Xtiene un valor nulo, esto conducirá a NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Pero si establece "la propiedad X nunca debe tener un valor nulo" como condición previa del método, puede evitar el escenario descrito anteriormente:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

Por esta causa, el proyecto de contratos de código existe para aplicaciones .NET.

Alternativamente, el diseño por contrato se puede aplicar utilizando aserciones .

ACTUALIZACIÓN: Vale la pena mencionar que el término fue acuñado por Bertrand Meyer en relación con su diseño del lenguaje de programación Eiffel .

Nick L.
fuente
2
Pensé agregar esto ya que nadie lo mencionó, y en la medida en que exista un enfoque, mi intención era enriquecer el tema.
Nick Louloudakis
2
Gracias por enriquecer el tema. He dado mi opinión sobre su incorporación. Ahora otros pueden hacer lo mismo.
John Saunders
2
Pensé que esto era una adición valiosa al tema dado que este es un hilo muy visto. He oído hablar de contratos de código antes y este fue un buen recordatorio para considerar usarlos.
VoteCoffee
36

Se NullReferenceExceptiongenera A cuando intentamos acceder a las Propiedades de un objeto nulo o cuando un valor de cadena se vacía y estamos intentando acceder a métodos de cadena.

Por ejemplo:

  1. Cuando se accede a un método de cadena de una cadena vacía:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. Cuando se accede a una propiedad de un objeto nulo:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 
Hemant Bavle
fuente
2
Esto es incorrecto. String.Empty.ToLower()no lanzará una excepción de referencia nula. Representa una cadena real, aunque vacía (es decir ""). Como esto tiene un objeto al que invocar ToLower(), no tendría sentido lanzar una excepción de referencia nula allí.
Kjartan
31

TL; DR: intente usar en Html.Partiallugar deRenderpage


Obtuve Object reference not set to an instance of an objectcuando traté de representar una Vista dentro de una Vista enviándole un Modelo, como este:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

La depuración mostró que el modelo era Nulo dentro de MyOtherView. Hasta que lo cambié a:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

Y funcionó.

Además, la razón por la que no tuve Html.Partialque comenzar fue porque Visual Studio a veces arroja líneas onduladas con aspecto de error Html.Partialsi está dentro de un foreachbucle de construcción diferente , aunque en realidad no es un error:

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
            @Html.Partial("MyOtherView.cshtml");
        }
    }
</div>

Pero pude ejecutar la aplicación sin problemas con este "error". Pude deshacerme del error cambiando la estructura del foreachbucle para que se vea así:

@foreach(var M in MyEntities){
    ...
}

Aunque tengo la sensación de que fue porque Visual Studio estaba leyendo mal los símbolos y los corchetes.

Travis Heeter
fuente
Querías Html.Partial, no@Html.Partial
John Saunders
Además, muestre qué línea arrojó la excepción y por qué.
John Saunders
El error ocurrió en MyOtherView.cshtml, que no incluí aquí, porque el Modelo no se estaba enviando correctamente (sí Null), así que sabía que el error estaba en cómo estaba enviando el Modelo.
Travis Heeter
22

¿Qué puedes hacer al respecto?

Aquí hay muchas buenas respuestas que explican qué es una referencia nula y cómo depurarla. Pero hay muy poco sobre cómo prevenir el problema o al menos facilitar su detección.

Verificar argumentos

Por ejemplo, los métodos pueden verificar los diferentes argumentos para ver si son nulos y arrojar un ArgumentNullException, una excepción obviamente creada para este propósito exacto.

El constructor para el ArgumentNullExceptionpar toma el nombre del parámetro y un mensaje como argumentos para que pueda decirle al desarrollador exactamente cuál es el problema.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Usar herramientas

También hay varias bibliotecas que pueden ayudar. "Resharper", por ejemplo, puede proporcionarle advertencias mientras escribe código, especialmente si usa su atributo: NotNullAttribute

Hay "Contratos de código de Microsoft" donde usa una sintaxis como la Contract.Requires(obj != null)que le da tiempo de ejecución y compilación de verificación: Introducción de contratos de código .

También hay "PostSharp" que le permitirá usar atributos como este:

public void DoSometing([NotNull] obj)

Al hacer eso y hacer que PostSharp forme parte de su proceso de compilación obj, se verificará que no es nulo en tiempo de ejecución. Ver: verificación nula PostSharp

Solución de código simple

O siempre puede codificar su propio enfoque utilizando un código antiguo simple. Por ejemplo, aquí hay una estructura que puede usar para capturar referencias nulas. Se basa en el mismo concepto que Nullable<T>:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull<T> notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull<T>(T value)
    {
        return new NotNull<T> { Value = value };
    }
}

Usaría una forma muy similar a la misma que usaría Nullable<T>, excepto con el objetivo de lograr exactamente lo contrario: no permitir null. Aquí hay unos ejemplos:

NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null

NotNull<T>está implícitamente emitido hacia y desde Tpara que pueda usarlo en cualquier lugar donde lo necesite. Por ejemplo, puede pasar un Personobjeto a un método que tome un NotNull<Person>:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull<Person> person)
{
    Console.WriteLine(person.Value.Name);
}

Como puede ver arriba, como con nulable, accedería al valor subyacente a través de la Valuepropiedad. Alternativamente, puede usar una conversión explícita o implícita, puede ver un ejemplo con el valor de retorno a continuación:

Person person = GetPerson();

public static NotNull<Person> GetPerson()
{
    return new Person { Name = "John" };
}

O incluso puede usarlo cuando el método simplemente regrese T(en este caso Person) haciendo un lanzamiento. Por ejemplo, al siguiente código le gustaría el código anterior:

Person person = (NotNull<Person>)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Combinar con extensión

Combine NotNull<T>con un método de extensión y puede cubrir incluso más situaciones. Aquí hay un ejemplo de cómo puede verse el método de extensión:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull<T>(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

Y aquí hay un ejemplo de cómo podría usarse:

var person = GetPerson().NotNull();

GitHub

Para su referencia, hice que el código anterior esté disponible en GitHub, puede encontrarlo en:

https://github.com/luisperezphd/NotNull

Característica relacionada del lenguaje

C # 6.0 introdujo el "operador nulo-condicional" que ayuda un poco con esto. Con esta función, puede hacer referencia a objetos anidados y, si alguno de ellos es nullla expresión completa, regresa null.

Esto reduce la cantidad de comprobaciones nulas que tiene que hacer en algunos casos. La sintaxis es poner un signo de interrogación antes de cada punto. Tome el siguiente código, por ejemplo:

var address = country?.State?.County?.City;

Imagine que countryes un objeto de tipo Countryque tiene una propiedad llamada Statey así sucesivamente. Si country, State, County, o Cityes nullentonces address will benula . Therefore you only have to check whetherdirección isnull`.

Es una gran característica, pero le brinda menos información. No hace obvio cuál de los 4 es nulo.

¿Incorporado como Nullable?

C # tiene una buena abreviatura para Nullable<T>, puede hacer que algo sea anulable poniendo un signo de interrogación después del tipo de esta manera int?.

Sería bueno si C # tenido algo así como la NotNull<T>estructura anterior y tenía una taquigrafía similares, tal vez el signo de exclamación para que usted podría escribir algo como (!): public void WriteName(Person! person).

Luis Pérez
fuente
2
Nunca arrojes NullReferenceException
John Saunders
@JohnSaunders me atrevo a preguntar ¿por qué? (¿En serio, por qué?)
Luis Pérez
2
NullReferenceException está destinado a ser lanzado por el CLR. Significa que se ha producido una referencia a un valor nulo. No significa que ocurra una referencia a un valor nulo, excepto que usted primero verificó hábilmente.
John Saunders
Veo su punto sobre cómo eso sería confuso. Lo actualicé a una excepción regular para este ejemplo y una excepción personalizada en GitHub.
Luis Perez
Gran respuesta para una pregunta tan básica. No es tan malo cuando es tu código el que falla. Es horrible cuando proviene de una biblioteca de terceros comercial en la que confía, y el servicio de atención al cliente sigue insistiendo en que tiene que ser su código el que está causando el problema. Y no estás del todo seguro de que no lo sea y todo el proyecto está paralizado. De hecho, creo que esto podría ser un epitafio apropiado para mi lápida: "La referencia de objeto no está establecida en una instancia de un objeto".
Darrel Lee
10

Curiosamente, ninguna de las respuestas en esta página menciona los dos casos extremos, espero que a nadie le importe si los agrego:

Caso límite # 1: acceso concurrente a un diccionario

Los diccionarios genéricos en .NET no son seguros para subprocesos y a veces pueden arrojar un NullReferenceo incluso (más frecuente) unKeyNotFoundException cuando intenta acceder a una clave desde dos subprocesos simultáneos. La excepción es bastante engañosa en este caso.

Caso de borde # 2: código inseguro

Si el código NullReferenceExceptionarroja una unsafe, puede mirar las variables de puntero y verificar siIntPtr.Zero o algo así. Lo que es lo mismo ("excepción de puntero nulo"), pero en el código inseguro, las variables a menudo se convierten en tipos / matrices de valores, etc., y te golpeas la cabeza contra la pared, preguntándote cómo un tipo de valor puede arrojar esto excepción.

(Por cierto, otra razón para no usar código inseguro a menos que lo necesite)

jazzcat
fuente
55
Su ejemplo de diccionario no es un caso límite. Si el objeto no es seguro para subprocesos, su uso desde múltiples subprocesos produce resultados aleatorios. ¿Su ejemplo de código inseguro difiere de nullqué manera?
John Saunders
10

Puede arreglar NullReferenceException de manera limpia utilizando operadores condicional nulo en c # 6 y escribir menos código para manejar las comprobaciones nulas.

Se utiliza para probar nulo antes de realizar una operación de acceso de miembro (?.) O índice (? [).

Ejemplo

  var name = p?.Spouse?.FirstName;

es equivalente a:

    if (p != null)
    {
        if (p.Spouse != null)
        {
            name = p.Spouse.FirstName;
        }
    }

El resultado es que el nombre será nulo cuando p sea nulo o cuando p.Spouse sea nulo.

De lo contrario, al nombre de la variable se le asignará el valor de p.Spouse.FirstName.

Para más detalles: Operadores condicional nulo

revs M.Hassan
fuente
9

La línea de error "Referencia de objeto no establecida en una instancia de un objeto" indica que no ha asignado un objeto de instancia a una referencia de objeto y que aún está accediendo a propiedades / métodos de ese objeto.

por ejemplo: supongamos que tiene una clase llamada myClass y contiene una propiedad prop1.

public Class myClass
{
   public int prop1 {get;set;}
}

Ahora está accediendo a este prop1 en alguna otra clase, como a continuación:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

la línea anterior arroja un error porque la referencia de la clase myClass se declara pero no se instancia o una instancia del objeto no se asigna a la referencia de esa clase.

Para solucionar esto, debe crear una instancia (asignar objeto a la referencia de esa clase).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
Jaimin Dave
fuente
4

NullReferenceException o la referencia de objeto no establecida en una instancia de un objeto se produce cuando un objeto de la clase que está intentando utilizar no se instancia. Por ejemplo:

Suponga que tiene una clase llamada Estudiante.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

Ahora, considere otra clase en la que está tratando de recuperar el nombre completo del alumno.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

Como se ve en el código anterior, la declaración Student s - solo declara la variable de tipo Student, tenga en cuenta que la clase Student no se instancia en este punto. Por lo tanto, cuando se ejecuta la instrucción s.GetFullName () , arrojará la NullReferenceException.

Mella
fuente
3

Bueno, en términos simples:

Está intentando acceder a un objeto que no está creado o que actualmente no está en la memoria.

Entonces, cómo abordar esto:

  1. Depura y deja que el depurador se rompa ... Te llevará directamente a la variable que está rota ... Ahora tu tarea es simplemente solucionar esto ... Usando la nueva palabra clave en el lugar apropiado.

  2. Si se produce en algunos comandos de la base de datos porque el objeto no está presente, entonces todo lo que necesita hacer es hacer una verificación nula y manejarlo:

    if (i == null) {
        // Handle this
    }
  3. El más difícil ... si el GC ya recolectó el objeto ... Esto generalmente ocurre si está tratando de encontrar un objeto usando cadenas ... Es decir, si lo encuentra por el nombre del objeto, puede suceder que el GC ya pueda lo limpió ... Esto es difícil de encontrar y se convertirá en un gran problema ... Una mejor manera de abordar esto es realizar comprobaciones nulas siempre que sea necesario durante el proceso de desarrollo. Esto te ahorrara mucho tiempo.

Al encontrar por nombre me refiero a que algún marco le permite FIndObjects usando cadenas y el código podría verse así: FindObject ("ObjectName");

Akash Chowdary
fuente
3
Si tiene una referencia a un objeto, entonces el GC nunca lo limpia
John Saunders
2
si usa cosas como FindObject ("Nombre del objeto") no hay manera de que GC sepa de antemano que va a hacer referencia a ese objeto ... esto es lo que estaba tratando de explicar ... esto ocurre en tiempo de ejecución
Akash Gutha
2
Hay algunos marcos que proporcionan esta funcionalidad en C #, como Unity. La pregunta no tiene nada relacionado con BCl. Busque en Internet antes de criticar que hay un montón de funciones como estas y para obtener información amable, incluso la uso a diario. Ahora por favor dime cómo la respuesta no tiene sentido.
Akash Gutha
2
docs.unity3d.com/ScriptReference/… revise el enlace y corríjalo rself mr.expert: p
Akash Gutha
Los ejemplos que vi en su enlace asignan los resultados de GameObject.Find a un campo miembro. Esa es una referencia y el GC no lo recopilará hasta que se recopile el objeto que lo contiene.
John Saunders
1

Literalmente, la forma más fácil de arreglar una NullReferenceExeption tiene dos formas. Si tiene un GameObject, por ejemplo, con un script adjunto y una variable llamada rb (cuerpo rígido), esta variable comenzará nula cuando inicie el juego.
Es por eso que obtiene una NullReferenceExeption porque la computadora no tiene datos almacenados en esa variable.

Usaré una variable RigidBody como ejemplo.
Podemos agregar datos realmente fácilmente de varias maneras:

  1. Agregue un RigidBody a su objeto con AddComponent> Physics> Rigidbody
    Luego ingrese a su script y escriba rb = GetComponent<Rigidbody>();
    Esta línea de código funciona mejor bajo sus funciones Start()o Awake().
  2. Puede agregar un componente mediante programación y asignar la variable al mismo tiempo con una línea de código: rb = AddComponent<RigidBody>();

Notas adicionales: Si desea la unidad para agregar un componente a su objeto y puede haber olvidado agregar uno, puede escribir [RequireComponent(typeof(RigidBody))]arriba de su declaración de clase (el espacio debajo de todos sus usos).
¡Disfruta y diviértete haciendo juegos!

CausticLasagne
fuente
-1

Si consideramos escenarios comunes donde se puede lanzar esta excepción, accedemos a las propiedades dentro del objeto en la parte superior.

Ex:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

aquí, si la dirección es nula, obtendrá NullReferenceException.

Por lo tanto, como práctica, siempre debemos usar la verificación nula, antes de acceder a las propiedades de dichos objetos (especialmente en genéricos)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Hiran
fuente
-3

Esto es básicamente una excepción de referencia nula . Como Microsoft Unidos-

Se produce una excepción NullReferenceException cuando intenta acceder a un miembro de un tipo cuyo valor es nulo.

Qué significa eso?

Eso significa que si algún miembro que no tiene ningún valor y estamos haciendo que ese miembro realice cierta tarea, el sistema indudablemente arrojará un mensaje y dirá:

"Oye, espera, ese miembro no tiene valores, por lo que no puede realizar la tarea que le estás entregando".

La excepción en sí dice que se está refiriendo algo pero cuyo valor no se está estableciendo. Esto denota que solo ocurre mientras se usan tipos de referencia, ya que los tipos de Valor no son anulables.

NullReferenceException no ocurrirá si estamos utilizando miembros de tipo Value.

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        Console.WriteLine(str.Length);
        Console.ReadLine();
    }
}

El código anterior muestra una cadena simple que se asigna con un valor nulo .

Ahora, cuando intento imprimir la longitud de la cadena str , recibo un mensaje de excepción no controlada del tipo 'System.NullReferenceException' porque el miembro str apunta a nulo y no puede haber ninguna longitud nula.

' NullReferenceException ' también ocurre cuando olvidamos instanciar un tipo de referencia.

Supongamos que tengo una clase y un método miembro. No he instanciado mi clase, sino que solo he nombrado mi clase. Ahora, si trato de usar el método, el compilador arrojará un error o emitirá una advertencia (dependiendo del compilador).

class Program
{
    static void Main(string[] args)
    {
        MyClass1 obj;
        obj.foo();  //Use of unassigned local variable 'obj'
    }
}

public class MyClass1
{
    internal void foo()
    {
        Console.WriteLine("hello from foo");

    }
}

El compilador para el código anterior genera un error de que la variable obj no está asignada, lo que significa que nuestra variable tiene valores nulos o nada. El compilador para el código anterior genera un error de que la variable obj no está asignada, lo que significa que nuestra variable tiene valores nulos o nada.

¿Por qué ocurre?

  • NullReferenceException surge debido a nuestra culpa por no verificar el valor del objeto. A menudo dejamos los valores del objeto sin marcar en el desarrollo del código.

  • También surge cuando olvidamos instanciar nuestros objetos. El uso de métodos, propiedades, colecciones, etc. que pueden devolver o establecer valores nulos también puede ser la causa de esta excepción.

¿Cómo se puede evitar?

Hay varias formas y métodos para evitar esta reconocida excepción:

  1. Comprobación explícita: debemos cumplir con la tradición de comprobar los objetos, propiedades, métodos, matrices y colecciones si son nulos. Esto se puede implementar simplemente usando declaraciones condicionales como if-else if-else, etc.

  2. Manejo de excepciones: una de las formas importantes de gestionar esta excepción. Usando simples bloques try-catch-finally podemos controlar esta excepción y también mantener un registro de la misma. Esto puede ser muy útil cuando su aplicación está en etapa de producción.

  3. Operadores nulos: el operador de fusión nula y los operadores condicionales nulos también se pueden usar a la vez que se configuran valores para objetos, variables, propiedades y campos.

  4. Depurador: para los desarrolladores, tenemos el gran arma de la depuración con nosotros. Si nos enfrentamos a NullReferenceException durante el desarrollo, podemos usar el depurador para llegar al origen de la excepción.

  5. Método incorporado: los métodos del sistema como GetValueOrDefault (), IsNullOrWhiteSpace () e IsNullorEmpty () comprueban nulos y asignan el valor predeterminado si hay un valor nulo.

Ya hay muchas buenas respuestas aquí. También puede consultar una descripción más detallada con ejemplos en mi blog .

Espero que esto ayude también!

Wasim
fuente
Básicamente copió la mitad de esa publicación de blog y no agregó nada nuevo que las respuestas existentes no aborden.
CodeCaster
@codecaster ¿Se dice copiar cuando reescribes un resumen de tu propio blog? Sé que no hay nada nuevo en mi respuesta y nada nuevo que las respuestas anteriores no tengan, pero deseo contribuir de una manera más sofisticada y dejar que otros entiendan la forma en que yo entendí. Se alegrará incluso si ayuda a una sola persona. De buena fe.
Wasim
-4

Si uno recibe este mensaje durante el guardado o la compilación de la compilación, simplemente cierre todos los archivos y luego abra cualquier archivo para compilar y guardar.

Para mí, la razón era que había cambiado el nombre del archivo y el archivo antiguo todavía estaba abierto.

Harshal Doshi Jain
fuente