it-swarm-es.tech

¿Qué es una NullReferenceException y cómo puedo solucionarlo?

Tengo algo de código y cuando se ejecuta, lanza una NullReferenceException, diciendo:

Referencia a objeto no establecida como instancia de un objeto.

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

1877
John Saunders

¿Cual es la causa?

Línea de fondo

Está intentando usar algo que es null (o Nothing en VB.NET). Esto significa que lo configuras en null, o nunca lo configuras en nada.

Como cualquier otra cosa, null se transmite. Si es nullin método "A", podría ser que el método "B" haya pasado nullto método "A".

null puede tener diferentes significados:

  1. Las variables de objeto que son sin inicializar y por lo tanto no apuntan a nada. En este caso, si accede a las propiedades o métodos de dichos objetos, se produce una NullReferenceException.
  2. El desarrollador está usando null intencionalmente para indicar que no hay un valor significativo disponible. Tenga en cuenta que C # tiene el concepto de tipos de datos que admiten nulos para las variables (como las tablas de base de datos pueden tener campos que admiten nulos): puede asignar null a ellas para indicar que no hay ningún valor almacenado en ellas, por ejemplo int? a = null;, donde el signo de interrogación indica que está permitido almacenar nulo en la variable a. Puede verificarlo con if (a.HasValue) {...} o con if (a==null) {...}. Las variables anulables, como a este ejemplo, permiten acceder al valor a través de a.Value explícitamente, o simplemente de la forma normal a través de a.
    Nota que acceder a él a través de a.Value arroja una InvalidOperationException en lugar de una NullReferenceException si a es null - debe hacer la verificación de antemano, es decir, si tiene otra variable con nullable int b;, entonces debe asignaciones como if (a.HasValue) { b = a.Value; } o más corta if (a != null) { b = a; }.

El resto de este artículo incluye más detalles y muestra los errores que muchos programadores suelen cometer, lo que puede llevar a una NullReferenceException.

Más específicamente

El tiempo de ejecución al lanzar una NullReferenceException siempre significa lo mismo: está intentando usar una referencia, y la referencia no está inicializada (o fue una vez inicializada, pero está no más largo inicializado).

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

string foo = null;
foo.ToUpper();

Esto arrojará una NullReferenceException a la segunda línea porque no puede llamar al método de instancia ToUpper() en una referencia string que apunta a null.

Depuración

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

Si desea saber dónde está o no está establecida 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 rompe en tal 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 espera que lo haga.

Al seguir el flujo del programa de esta manera, puede encontrar la ubicación donde la instancia no debería 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ás una 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, el HttpContext.Current podría ser nulo, o la propiedad User podría ser nula, o la propiedad Identity 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 principal (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 se usa la palabra clave new, solo crea una nueva instancia de Book, pero no una nueva instancia de Person, por lo que Author la 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; }
}

Los inicializadores de colección anidados se comportan de la misma manera:

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 solo crea una instancia de Person, pero la colección Books sigue siendo null. La sintaxis del inicializador de colección no crea una colección para p1.Books, solo se traduce a las declaraciones p1.Books.Add(...).

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.

Variable de rango (indirecta/diferida)

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

Malas convenciones de nomenclatura:

Si nombró campos de manera diferente a los locales, es posible que se haya dado cuenta de que nunca inicializó el campo.

public class Form1 {
    private Customer customer;

    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 de ASP.NET

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

ASP.NET MVC modelos de vista vacía

Si la excepción se produce al hacer referencia a una propiedad de @Model en una vista MVC de ASP.NET, debe comprender que Model se establece en su método de acción, cuando return una vista. Cuando devuelve un modelo vacío (o propiedad de modelo) de su controlador, la excepción se produce cuando las vistas acceden al mismo:

// 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 -->

WPF Control Creation Order and Events

Los controles WPF se crean durante la llamada a InitializeComponent en el orden en que aparecen en el árbol visual. Una NullReferenceException se generará en el caso de los controles creados al principio con controladores de eventos, etc., que se activarán durante la InitializeComponent que hacen referencia a los controles creados tardíamente.

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í comboBox1 se crea antes de label1. Si comboBox1_SelectionChanged intenta 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, listar label1 antes de comboBox1, ignorando los problemas de la filosofía de diseño, al menos resolvería la NullReferenceException aquí.

Reparto con as

var myThing = someObject as Thing;

Esto no lanza una excepción InvalidCastException, pero devuelve una null cuando la conversión falla (y cuando someObject es nulo). Así que sé consciente de eso.

LINQ FirstOrDefault () y SingleOrDefault ()

Las versiones simples First() y Single() lanzan excepciones cuando no hay nada. Las versiones "OrDefault" devuelven un valor nulo en ese caso. Así que sé consciente de eso.

para cada

foreach lanza cuando intentas iterar la colección nula. Usualmente causada por el inesperado resultado de null de métodos que devuelven colecciones.

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

Ejemplo más realista: seleccione los nodos del documento XML. Se lanzará si no se encuentran los 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 null e ignore los valores nulos.

Si espera que la referencia a veces sea nula, puede verificar que sea null antes de acceder a los miembros de la instancia:

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

Verifique explícitamente null y proporcione un valor predeterminado.

Los métodos de llamada que espera devolver una instancia pueden devolver null, por ejemplo, cuando no se puede encontrar el objeto que se está buscando. 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 null desde las llamadas a métodos y lance una excepción personalizada.

También puede lanzar una excepción personalizada, solo para capturarla 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.Assert si un valor nunca debe ser null, para detectar el problema antes de que ocurra la excepción.

Cuando sabe durante el desarrollo que un método tal vez pueda, pero nunca debe devolver null, puede usar Debug.Assert() para interrumpir lo antes posible cuando ocurra:

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 compilación de lanzamiento , causando que NullReferenceException vuelva a aparecer cuando book == null en tiempo de ejecución en modo de lanzamiento.

Utilice GetValueOrDefault() para los tipos de valores que puedan contener nulos para proporcionar un valor predeterminado cuando son 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

Use el operador de unión nula: ?? [C #] o If() [VB].

La abreviatura para proporcionar un valor predeterminado cuando se encuentra una null:

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

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

Esto también a veces se denomina 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 el lado derecho no se evaluará, y en su lugar se devuelve 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á tratando de llamar a ToUpper en una propiedad con un valor nulo.

En C # 5 y más abajo, esto puede ser protegido 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 que la variable de título sea null, y la llamada a ToUpper no se realizará si person.Title es null.

Por supuesto, usted aún tiene que verificar title para nulo o usar el operador de condición nula junto con el operador de unión nula (??) 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] de la siguiente manera:

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

Esto hará lo siguiente: Si myIntArray es nulo, la expresión devuelve un valor nulo y puede verificarlo de manera segura. Si contiene una matriz, hará lo mismo que: elem = myIntArray[i]; y devuelve el ith elemento.

Técnicas especiales para depurar y reparar errores nulos en iteradores.

C # admite "bloques de iteradores" (llamados "generadores" en otros lenguajes populares). Las excepciones de anulación de nulos pueden ser particularmente difíciles de depurar en bloques de 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 whatever da como resultado null entonces MakeFrob lanzará. Ahora, puedes 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? Debido a que el bloque iterador en realidad no ejecutar hasta la foreach! La llamada a GetFrobs simplemente devuelve un objeto que cuando se itera ejecutará el bloque del iterador.

Al escribir una marca nula como esta, previene la anulación nula, pero mueve la excepción de argumento nulo al punto de iteración, no al punto de 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 bloque del iterador y un método de superficie pública que haga la comprobación nula y devuelva el iterador. Ahora, cuando se llama a GetFrobs, la comprobación de nulos ocurre inmediatamente, y luego GetFrobsForReal se ejecuta cuando se itera la secuencia.

Si examina la fuente de referencia de LINQ to Objects, verá que esta técnica se utiliza en todo momento. Escribir es un poco más torpe, pero facilita mucho la depuración de errores de nulidad. Optimice su código para la conveniencia de la persona que llama, no la conveniencia del autor .

Una nota sobre nereferencias en código inseguro

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

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

  • la desreferenciación de un nulo puntero produce la misma excepción que la desreferenciación de un nulo referencia
  • desreferenciación de un puntero no nulo no válido can produce esa excepción en algunas circunstancias

Para comprender por qué esto es así, es útil comprender cómo .NET genera excepciones de anulación de nulos 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 la memoria tiene indicadores establecidos que determinan cómo se puede usar: leer, escribir, ejecutar, etc. La página la más baja está marcada como "produce un error si alguna vez se utiliza de alguna manera".

Tanto un puntero nulo como una referencia nula en 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 de .NET luego detecta este error y lo convierte en la excepción de anulación nula.

Es por eso que al eliminar la referencia tanto de un puntero nulo como de una referencia nula se produce la misma excepción.

¿Qué pasa con el segundo punto? La anulación de referencia cualquiera puntero no válido que se encuentra 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 ints y un puntero no administrado igual a nulo. Si intentamos eliminar la referencia al segundo int en la estructura, el CLR no intentará acceder al almacenamiento en la ubicación cero; Accederá al almacenamiento en la ubicación cuatro. Pero lógicamente esto es una falta de referencia nula porque estamos llegando a esa dirección a través de la nula.

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

2258
John Saunders

Excepción de referencia nula - Visual Basic

El _NullReference Exception_ para 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 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 probablemente listado 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 Objeto" 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 lo inicializó (creó una instancia o ' instanciar 'it)
  • 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 de objeto que es Nothing, la respuesta es examinarlos para descubrir 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.

IDE debug display

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 causa.

Una MsgBox en la Captura que muestra _Error while..._ será de poca ayuda. Este método también conduce 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_ ( Debug -> Windows -> Locals ) 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 Dim no crea un objeto CashRegister ; solo declara una variable llamada reg de ese tipo. Declarar una variable de objeto y crear una instancia son dos cosas diferentes.

Remedio

El operador New 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 use Dim nuevamente 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 local , reg, que existe solo en ese contexto (sub). La variable reg con nivel de módulo Scope que usará en cualquier otro lugar sigue siendo Nothing.

Falta el operador New es la causa # 1 de _NullReference Exceptions_ visto en las preguntas de Stack Overflow revisadas.

Visual Basic intenta aclarar el proceso repetidamente usando New: Usando New El operador crea un nuevo objeto y llama Sub New - - el 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 mediante donde se declara _Private | Friend | Public_ define el nivel de acceso, no Ámbito .

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: Comenzando con VS 2010, cuando se inicializa una matriz local usando un literal y _Option Infer_, los elementos _As <Type>_ y New son 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 todavía 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 objetos Foo en ella 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 una 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: myList solo 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 barList solo se declara, no se instancia. Crear una instancia de Foo tampoco creará una instancia de barList interna. 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 obtener más información, vea List(Of T) Class .


Objetos de proveedor de datos

Trabajar con bases de datos presenta muchas oportunidades para una referencia nula porque puede haber muchos objetos (Command, Connection, Transaction, Dataset, DataTable, DataRows....) en uso a la vez. Nota: No importa qué proveedor de datos esté utilizando: MySQL, SQL Server, OleDB, etc. - the los conceptos son iguales.

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, se declaró el objeto de conjunto de datos ds, pero nunca se creó una instancia. La DataAdapter llenará una DataSet existente, no creará una. En este caso, dado que ds es 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 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í: Employees vs Employee. No se creó DataTable llamado "Empleado", por lo que se genera un NullReferenceException tratando de acceder a él. Otro problema potencial es asumir que habrá Items que puede no ser así cuando el SQL incluye una cláusula WHERE.

Remedio

Como esto usa una tabla, usar Tables(0) evitará errores ortográficos. Examinar _Rows.Count_ tambié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
_

Fill es una función que devuelve el número de Rows afectado 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
_

DataAdapter proporcionará TableNames como se muestra en el ejemplo anterior, pero no analiza los nombres de la tabla SQL o de la base de datos. Como resultado, ds.Tables("TICKET_RESERVATION") hace 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 Clase DataTable .


Rutas de objeto/anidadas

_If myFoo.Bar.Items IsNot Nothing Then
   ...
_

El código solo prueba Items mientras que myFoo y Bar también pueden ser Nothing. El remedio es probar toda la cadena o ruta de los objetos de uno en uno:

_If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....
_

AndAlso es importante. Las pruebas posteriores no se realizarán una vez que se encuentre la primera condición False. Esto permite que el código 'se desplace' de forma segura en el (los) objeto (s) un 'nivel' a la vez, evaluando _myFoo.Bar_ solo después (y si) myFoo se 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 objeto null. Esto también se aplica a los controles:

_myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
_

Aquí, myWebBrowser o Document podría ser Nothing o el elemento _formfld1_ 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.SelectedItem_ bien puede ser Nothing, por lo que _ListBox1.SelectedItem.ToString_ dará como resultado una NRE.

Remedio

Valide los datos antes de usarlos (también use los parámetros _Option Strict_ y 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, puede 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 se codifica, el IDE informará que Controls no existe en el contexto actual, o "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 el constructor crea Form o Controls. Como resultado:

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

Hacer referencia a elementos de la matriz más adelante dará como resultado una NRE. Si hace esto en _Form_Load_, debido a un error extraño, el IDE puede no informar la excepción cuando sucede. La excepción aparecerá más tarde cuando su código intente usar la matriz. Esta "excepción silenciosa" es detallada en esta publicación . Para nuestros propósitos, la clave es que cuando ocurre algo catastrófico mientras se crea un formulario (evento _Sub New_ o _Form Load_), las excepciones pueden no informarse, el código sale del procedimiento y solo muestra el formulario.

Como ningún otro código en su evento _Sub New_ o _Form Load_ se ejecutará después de la NRE, muchas otras cosas pueden dejarse sin inicializar.

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

Nota esto se aplica a todas y cada una de las referencias de control y componentes, lo que las hace 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 formulario, pero inicializar en el controlador de eventos de carga de formulario cuando los controles existen . Esto se puede hacer en _Sub New_ siempre que su código esté después de la llamada InitializeComponent:

_' 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 se encuentran en un control de contenedor (como GroupBox o 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, Nothing nuevamente se almacenará 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 shows you the error of your ways

"Button2" reside en un Panel

Remedio

En lugar de referencias indirectas por nombre usando la colección Controls 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 IDE le advertirá que ' no todas las rutas devuelven un valor y puede resultar un NullReferenceException'. Puede suprimir la advertencia, reemplazando _Exit Function_ por _Return Nothing_, pero eso no resuelve el problema. Cualquier cosa que intente usar el retorno cuando _someCondition = False_ dará como resultado una NRE:

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

Remedio

Reemplace _Exit Function_ en la función con _Return bList_. Devolver un vacío List no es lo mismo que devolver Nothing. Si existe la posibilidad de que un objeto devuelto pueda ser 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 Catch vacío.

Hay una coma adicional en el SQL (después de 'mailaddress') que da como resultado una excepción en _.ExecuteReader_. Después de que Catch no hace nada, Finally intenta realizar la limpieza, pero como no puede Close un objeto DataReader nulo, se obtiene un NullReferenceException completamente nuevo.

Un bloque Catch vacío es el patio del diablo. Este OP estaba desconcertado por qué estaba obteniendo una NRE en el bloque Finally. En otras situaciones, un Catch vacío puede ocasionar que algo mucho más lejos se vuelva loco y hacer que pierda tiempo buscando las cosas incorrectas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).

Remedio

No utilice 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 función IsDBNull se usa para probar si un valor es igual a _System.DBNull_: De 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
       ...
_

FirstOrDefault devuelve el primer elemento o el valor predeterminado, que es Nothing para los tipos de referencia y nunca DBNull:

_If getFoo IsNot Nothing Then...
_

Controles

_Dim chk As CheckBox

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

Si no se puede encontrar una CheckBox con chkName (o existe en una GroupBox), entonces chk será Nothing e intentar hacer referencia a cualquier propiedad resultará en 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 dgvBooks tiene _AutoGenerateColumns = True_, creará las columnas, pero no las nombrará, por lo que el código anterior falla cuando las referencia por 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 su DataGridView tiene AllowUserToAddRows como True (por defecto), la Cells en 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 bucle _For/Each_ y pruebe la propiedad IsNewRow para determinar si es esa última fila. Esto funciona si AllowUserToAddRows es verdadero o no:

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

Si usa un bucle _For n_, modifique el recuento de filas o use _Exit For_ cuando IsNewRow es verdadero.


My.Settings (StringCollection)

En ciertas circunstancias, intentar usar un elemento de _My.Settings_ que es una StringCollection puede resultar en una referencia nula 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 colección. Lo hará, pero solo si ha agregado previamente una entrada inicial a la colección (en el editor de Configuración). Dado que la colección se inicializa (aparentemente) cuando se agrega un elemento, permanece Nothing cuando no hay elementos en el editor de Configuración para agregar.

Remedio

Inicialice la colección de configuraciones en el controlador de eventos Load del formulario, si/cuando sea necesario:

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

Por lo general, la colección Settings 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 y luego elimine el valor falso.


Puntos clave

Probablemente olvidó el operador New.

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

302

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á una NullReferenceException sobre el reparto. Parece bastante obvio en el ejemplo anterior, pero esto puede suceder en escenarios más complejos e "de enlace tardío" en los que el objeto nulo se ha devuelto desde algún código que no posee, y la conversión se genera, por ejemplo, por algún sistema automático.

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

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

Aquí, SelectedDate es de hecho una propiedad - de DateTime tipo - del tipo Calendar Web Control, y el enlace podría devolver algo nulo perfectamente. El generador de ASP.NET implícito creará un fragmento de código que será equivalente al código de conversión anterior. Y esto generará una NullReferenceException que es bastante difícil de detectar, porque se encuentra en el código generado por ASP.NET que compila bien ...

223
Simon Mourier

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

SqlConnection connection = null;
connection.Open();

Eso generará el error porque, si bien he declarado la variable "connection", no apunta a nada. Cuando trato de llamar al miembro "Open", no hay ninguna referencia para que lo resuelva, 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 nula, lo que le permite poner una comprobación nula. Este error es la fuente número uno de errores, IMHO.

154
Chris B. Behrens

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 se deben probar con un valor 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
}
150
Jonathan Wood

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

Está intentando usar una variable de referencia cuyo valor es Nothing/null. Cuando el valor es Nothing/null para 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, ni estableció la variable en Nothing/null manualmente, o llamó a una función que configuró la variable en Nothing/null para usted.

94
code master

Un ejemplo de esta excepción que se lanza es: cuando intenta verificar algo, 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 lanzará una NullReferenceException cuando intentes realizar una acción en algo que no se haya instanciado, es decir, el código anterior.

En comparación con una ArgumentNullException que normalmente 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á enC # NullReferenceException y parámetro nulo.

85
Alex KeySmith

Si no ha inicializado un tipo de referencia y desea configurar o leer una de sus propiedades, lanzará 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 tipos de valor y tipos de referencia .

Entonces, si está tratando con tipos de valor , NullReferenceExceptions puede no ocurrir. Aunque necesita estar alerta cuando se trata de 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 estar marcados):

  • dinámica
  • objeto
  • cuerda

Tipos de valor (simplemente puede ignorar estos):

  • Tipos numericos
  • Tipos integrales
  • Tipos de punto flotante
  • decimal
  • bool
  • Estructuras definidas por el usuario
81
Fabian Bigler

Otro caso en el que puede ocurrir NullReferenceExceptions es el uso (incorrecto) del operador as :

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í, Book y Car son tipos incompatibles; una Car no se puede convertir/convertir en una Book. Cuando falla esta conversión, as devuelve null. Usar mybook después de esto provoca una NullReferenceException.

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

Si está esperando que la conversión de tipo siempre tenga éxito (es decir, sabe lo que el objeto debería estar adelantado), entonces debe usar una conversión:

ComicBook cb = (ComicBook)specificBook;

Si no está seguro del tipo, pero quiere probar para usarlo como un tipo específico, use as:

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}
75

Está utilizando el objeto que contiene la referencia de valor nulo. Así que 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 ()

63
user1814380

Mientras que what causa una NullReferenceExceptions y se acerca a Avoid/fix dicha excepción se ha abordado en otras respuestas, lo que muchos programadores no han aprendido aún es cómo independientemente depurar tales excepciones durante el desarrollo.

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


Primero, asegúrese de que se detectará el error correcto - vea ¿Cómo permito romper en 'System.NullReferenceException' en VS2010? Nota1

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 , que le pedirá que inicie el depurador.

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

Por ejemplo, en la siguiente línea, el único código que can cause la excepción es si myString se evalúa como nulo. Esto se puede verificar mirando el Ventana de visualizació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 (Ver o Windows Inmediato) para inspeccionar las expresiones para determinar si str1 fue nulo o si str2 fue nulo.

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

Una vez que donde se ha localizado la excepción de lanzamiento, es generalmente trivial razonar al revés para averiguar dónde se introdujo [incorrectamente] el valor nulo -

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


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

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 lanzan fuera de My Code y no pasan por My Code

59
user2864740

Simon Mourier dio este ejemplo :

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

donde ununboxingconversion (cast) fromobject (o de una de las clases System.ValueType o System.Enum, o de un tipo de interfaz) to un tipo de valor (distinto de Nullable<>) en sí mismo da NullReferenceException.

En la otra dirección, unboxingconversion from a Nullable<> que tiene HasValue igual a falseto un tipo de referencia, puede dar un null Referencia que luego puede llevar a una 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 usa el tiempo de ejecución cuando se recalcan las instancias de Nullable<>.

55
Jeppe Stig Nielsen

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

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

Luego, el siguiente código lanzará 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

Por el bien de la clase DataContext completa

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 extenderlas a otros archivos.

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

El error se produce cuando tanto la entidad como la clase de código están en el mismo espacio de nombres. Para solucionar este problema, cambie el nombre de la clase de entidad o la clase de código de enlace para Contact.aspx.

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

Para discusión, vea NullReferenceException en DbContext.saveChanges ()

40
AbhinavRanjan

Otro caso general en el que uno podría recibir esta excepción involucra clases de burla durante las pruebas de unidad. Independientemente de la estructura de simulacros que se esté utilizando, debe asegurarse de que todos los niveles apropiados de la jerarquía de clases estén debidamente burlados. En particular, todas las propiedades de HttpContext a las que hace referencia el código bajo prueba deben ser simuladas.

Consulte " NullReferenceException lanzada al probar el atributo de autorización personalizado " para ver un ejemplo un tanto detallado.

39
John Saunders

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

Cuando se trabaja a través de diferentes capas , por ejemplo, en una aplicación MVC, un controlador necesita servicios para realizar operaciones comerciales. En tales escenarios Dependency Injection Container puede usarse para inicializar los servicios para evitar la NullReferenceException . Así que eso significa que no tiene que preocuparse por verificar el valor nulo y simplemente llamar a los servicios desde el controlador como si siempre estuvieran disponibles (e inicializados) como singleton o 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();
    }
}
38
Mukus

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

Una forma más "formal" de prevenir tales condiciones de error mientras se desarrolla está aplicando diseño por contrato en su código. Esto significa que necesita configurar la clase invariantes, y/o incluso la función/método condiciones previas y postcondiciones en su sistema, mientras se desarrolla.

En resumen, invariantes de clase asegura que habrá algunas restricciones en tu clase que no se violarán en el uso normal (y, por lo tanto, la clase no se pondrá en un estado inconsistente). Condiciones previas significa que los datos proporcionados como entrada a una función/método deben seguir algunas restricciones establecidas y nunca violarlas, y postcondiciones significa que la salida de una función/método debe sigue las restricciones establecidas de nuevo sin violarlas nunca. Las condiciones del contrato deben nunca violarse durante la ejecución de un programa sin errores, por lo tanto, el diseño por contrato se verifica en la práctica en el modo de depuración, mientras que deshabilitado en versiones, para maximizar el sistema desarrollado actuación.

De esta manera, puede evitar NullReferenceException casos que son el resultado de la violación del conjunto de restricciones. Por ejemplo, si utiliza una propiedad de objeto X en una clase y luego intenta invocar uno de sus métodos y X tiene un valor nulo, esto llevará 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, entonces puede evitar el escenario descrito anteriormente:

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

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

Alternativamente, el diseño por contrato puede aplicarse 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 de Eiffel .

37
Nick Louloudakis

Se lanza una NullReferenceException cuando intentamos acceder a las Propiedades de un objeto nulo o cuando un valor de cadena se vacía y estamos tratando de acceder a los 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 
    
34
Hemant Bavle

TL; DR: Intente usar Html.Partial en lugar de Renderpage


Estaba obteniendo Object reference not set to an instance of an object cuando intenté renderizar 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 tenía Html.Partial para empezar era porque Visual Studio a veces arroja líneas onduladas con aspecto de error bajo Html.Partial si está dentro de un bucle foreach construido de manera 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 bucle foreach para tener este aspecto:

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

Aunque tengo la sensación de que fue porque Visual Studio estaba malinterpretando los símbolos y los paréntesis.

30
Travis Heeter

¿Qué puedes hacer al respecto?

Aquí hay muchas respuestas buenas 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 la captura.

Revisar argumentos

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

El constructor de la ArgumentNullException 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 el código, especialmente si usa su atributo: NotNullAttribute

Hay "Contratos de código de Microsoft" en los que se utiliza una sintaxis como Contract.Requires(obj != null) que le brinda verificación en tiempo de ejecución y compilación: Introducción a los contratos de código .

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

public void DoSometing([NotNull] obj)

Al hacer eso y hacer que PostSharp sea parte de su proceso de compilación, obj se comprobará como nulo en el tiempo de ejecución. Ver: PostSharp cheque nulo

Solución de código simple

O siempre puede codificar su propio enfoque utilizando un código antiguo. 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 muy similar a la misma manera 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> se convierte implícitamente en T para que pueda usarlo en cualquier lugar que lo necesite. Por ejemplo, puede pasar un objeto Person 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 nullable, accedería al valor subyacente a través de la propiedad Value. Alternativamente, puede usar una conversión explícita o implícita, puede ver un ejemplo con el siguiente valor de retorno:

Person person = GetPerson();

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

O incluso puedes usarlo cuando el método simplemente devuelve T (en este caso Person) haciendo un lanzamiento. Por ejemplo, el siguiente código le gustaría simplemente 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 podrá 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, puse el código arriba disponible en GitHub, lo puede encontrar en:

https://github.com/luisperezphd/NotNull

Característica del lenguaje relacionado

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

Esto reduce el número de cheques nulos que tiene que hacer en algunos casos. La sintaxis es poner un signo de interrogación antes de cada punto. Toma el siguiente código por ejemplo:

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

Imagine que country es un objeto de tipo Country que tiene una propiedad llamada State y así sucesivamente. Si country, State, County o City es null entonces address will benull. Therefore you only have to check whetheraddressisnull`.

Es una gran característica, pero le da menos información. No deja en claro cuál de los 4 es nulo.

¿Como Nullable incorporado?

C # tiene una abreviatura de Niza para Nullable<T>, puede hacer algo anulable colocando un signo de interrogación después del tipo, por lo que int?.

Sería bueno si C # tuviera algo como la estructura NotNull<T> anterior y tuviera una taquigrafía similar, tal vez el signo de exclamación (!) Para poder escribir algo como: public void WriteName(Person! person).

22
Luis Perez

Puede arreglar NullReferenceException de una manera limpia utilizando Operadores con Condición Nula en c # 6 y escribir menos código para manejar las verificaciones nulas.

Se utiliza para probar el valor 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 nulos condicionales

9
M.Hassan

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

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

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

Ahora está accediendo a esta 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 produce un error porque la referencia de la clase myClass se declara pero no se crea una 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;  
     }
}
8
Jaimin Dave

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

Caso de Edge # 1: acceso concurrente a un Diccionario

Los diccionarios genéricos en .NET no son seguros para subprocesos y a veces pueden lanzar una NullReference o incluso (más frecuente) una KeyNotFoundException cuando intenta acceder a una clave desde dos subprocesos concurrentes. La excepción es bastante engañosa en este caso.

Caso de Edge # 2: código inseguro

Si una NullReferenceException es lanzada por el código unsafe, puede mirar sus variables de puntero y verificarlas para IntPtr.Zero o algo así. Que es lo mismo ("excepción de puntero nulo"), pero en el código no seguro, las variables a menudo se convierten a tipos de valor/arrays, etc., y golpeas tu cabeza contra la pared, preguntándote cómo un tipo de valor puede lanzar esto excepción.

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

8
jazzcat

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

Supongamos que tienes 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á intentando recuperar el nombre completo del estudiante.

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 de Student no está instanciada en este punto. Por lo tanto, cuando la sentencia s.GetFullName () se ejecute, lanzará la NullReferenceException.

3
Nick

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. Depure y deje que el depurador se rompa ... Lo llevará directamente a la variable que está quebrada ... Ahora su tarea es simplemente arreglar esto ... Usando la palabra clave new en el lugar apropiado.

  2. Si se produce en algunos comandos database porque el objeto no está presente, todo lo que debe hacer es realizar una comprobación nula y manejarlo:

    if (i == null) {
        // Handle this
    }
    
  3. La más difícil ... si elGCya recolectó el objeto ... Esto generalmente ocurre si estás tratando de encontrar un objeto usando cadenas ... Es decir, encontrándolo por nombre del objeto, entonces puede suceder que el GC ya lo haya limpiado ... Esto es difícil de encontrar y se convertirá en un problema ... Una mejor manera de abordar esto es hacer verificaciones nulas cuando sea necesario durante el proceso de desarrollo. Esto te ahorrara mucho tiempo.

Al buscar por nombre me refiero a que algún marco te permite usar FIndObjects usando cadenas y el código podría tener este aspecto: FindObject ("ObjectName");

2
Akash Gutha

Literalmente, la manera más fácil de arreglar una NullReferenceExeption tiene dos formas. Si tienes un GameObject, por ejemplo, con un script adjunto y una variable llamada rb (rigidbody), esta variable comenzará nula cuando comiences tu juego.
Es por esto que obtienes 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> Física> Rigidbody
    Luego ve a tu script y escribe rb = GetComponent<Rigidbody>();
    Esta línea de código funciona mejor bajo sus funciones Start() o Awake().
  2. Puede agregar un componente programáticamente y asignar la variable al mismo tiempo con una línea de código: rb = AddComponent<RigidBody>();

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

0
CausticLasagne

Si consideramos escenarios comunes donde se puede lanzar esta excepción, acceder 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 utilizar la comprobación nula, antes de acceder a las propiedades en 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
0
Hiran