referencia - validar objeto vacio c#




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

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?


¿Cual es la causa?

Línea de fondo

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

Como cualquier otra cosa, null se pasa alrededor. Si es null en el método "A", podría ser que el método "B" pasó un null al método "A".

null puede tener diferentes significados:

  1. Las variables de objeto que están sin inicializar y por lo tanto apuntan a nada. En este caso, si accede a las propiedades o métodos de dichos objetos, se genera una NullReferenceException .
  2. El desarrollador está utilizando 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 null ): puede asignarles un null para indicar que no hay ningún valor almacenado, por ejemplo, int? a = null; 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 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 .
    Tenga en cuenta que acceder a él a través de a.Value lanza una InvalidOperationException lugar de una NullReferenceException si a es null : debe hacer la comprobación de antemano, es decir, si tiene otra variable int b; nullable int b; entonces deberías hacer asignaciones como if (a.HasValue) { b = a.Value; } if (a.HasValue) { b = a.Value; } o más corto if (a != null) { b = a; } if (a != null) { b = a; } .

El resto de este artículo es más detallado y muestra los errores que muchos programadores suelen cometer, lo que puede generar 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 se inicializa (o una vez se inicializó, pero ya no se inicializa).

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 lanzará una NullReferenceException en la segunda línea porque no puede llamar al método de instancia ToUpper() en una referencia de string apunta a null .

Depuración

¿Cómo encuentra 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 e inspeccione sus variables , ya sea colocando el mouse sobre sus nombres, abriendo un ( Rápido) Vea la ventana o utilice 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á 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 , 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 new palabra clave, solo crea una nueva instancia de Book , pero no una nueva instancia de Person , por lo que el 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 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" });

La 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 p1.Books.Add(...) .

Formación

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

Array Elements

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 el 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. Se generará una NullReferenceException en el caso de los controles creados anteriormente con controladores de eventos, etc., que se activan durante 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í se crea label1 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 un null cuando falla la conversión (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 nulo en ese caso. Así que sé consciente de eso.

para cada

foreach lanza cuando intentas iterar la colección nula. Usualmente causado por resultados null inesperados 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 si hay valores null e ignore 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 el null y proporcione un valor predeterminado.

Los métodos de llamada que espera devolver una instancia pueden devolver un 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 el null de 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;
}

Utilice Debug.Assert si un valor nunca debe ser null , para detectar el problema antes de que se produzca la excepción.

Cuando sabe durante el desarrollo que un método tal vez pueda, pero nunca debe devolver un null , puede usar Debug.Assert() para interrumpirse 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 comprobación no terminará en su versión de lanzamiento , causará que se vuelva a lanzar la NullReferenceException cuando book == null en el tiempo de ejecución en el modo de lanzamiento.

Use GetValueOrDefault() para tipos de valores que admiten valores null 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

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

La abreviatura para proporcionar un valor predeterminado cuando se encuentra un valor 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;
}

Utilice el operador de condición nula: ?. o ?[x] para 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á intentando 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 realice si person.Title es null .

Por supuesto, todavía tiene que verificar el 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 matrices puede usar ?[i] 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 elemento i th .

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 resultado es 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? ¡Porque el bloque iterador no se ejecuta realmente hasta el foreach ! La llamada a GetFrobs simplemente devuelve un objeto que, cuando se itera , ejecutará el bloque del iterador.

Al escribir una comprobación nula como esta, se evita la anulación de la nula, pero se 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 la depuración .

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 nula se realiza inmediatamente y, a continuación, GetFrobsForReal 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 complicado, 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 puntero nulo produce la misma excepción que la desreferenciación de una referencia nula
  • la anulación de la referencia de un puntero no nulo no válido puede producir esa excepción en algunas circunstancias

Para entender por qué esto es así, es útil entender cómo .NET produce excepciones de anulación de nulos en primer lugar. (Estos detalles se aplican a .NET que se ejecuta en Windows; otros sistemas operativos usan 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 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 la anulación de referencias tanto a un puntero nulo como a una referencia nula produce la misma excepción.

¿Qué pasa con el segundo punto? La eliminación de referencias 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 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 anulación de nulas porque estamos llegando a esa dirección a través de la nula.

Si está trabajando con un código no seguro y obtiene una excepción de anulación de nulos, simplemente 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.


Excepción de referencia nula - Visual Basic

La NullReference Exception para Visual Basic no es diferente de la de C # . Después de todo, ambos reportan la misma excepción definida en el .NET Framework que ambos usan. Las causas únicas de Visual Basic son raras (quizás solo una).

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

Nota:

  1. Esto se basa en conceptos: no hay código para pegar en su proyecto. Está pensado para ayudarlo a comprender las causas de una NullReferenceException (NRE), cómo encontrarlo, cómo solucionarlo y cómo evitarlo. Una NRE puede ser causada de muchas maneras, por lo que es poco probable que este sea su único encuentro.
  2. Los ejemplos (de publicaciones de desbordamiento de pila) no siempre muestran la mejor manera de hacer algo en primer lugar.
  3. Normalmente, se utiliza el remedio más simple.

Significado básico

El mensaje "Objeto no establecido en una instancia de Objeto" significa que está intentando usar 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 'la instancia ')
  • Algo que su código supuso inicializaría un objeto, no lo hizo
  • Posiblemente, otro código invalidó prematuramente un objeto todavía en uso

Encontrar la causa

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

También debe eliminar cualquier bloque Try / Catch del código relevante, especialmente aquellos donde no hay nada en el bloque Catch. Esto provocará que su código se bloquee cuando intenta usar un objeto que es Nothing . Esto es lo que desea, ya que identificará la ubicación exacta del problema y le permitirá identificar el objeto que lo causa.

Un MsgBox en el Catch que muestra Error while... será de poca ayuda. Este método también conduce a muy malas preguntas de desbordamiento de pila, porque no puede describir la excepción real, el objeto involucrado o incluso la línea de código donde ocurre.

También puede usar la 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 arreglar y más rápido que publicar una nueva pregunta.

Ver también:

Ejemplos y remedios

Objetos de clase / Creación de 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 New operador puede usarse a menudo para crear la instancia cuando la declara:

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 utilice 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 el Scope nivel de módulo que utilizará en cualquier otro lugar permanece en Nothing .

Falta el New operador es la causa número 1 de las NullReference Exceptions de NullReference Exceptions de NullReference Exceptions observadas en las preguntas de desbordamiento de pila revisadas.

Visual Basic intenta aclarar el proceso repetidamente utilizando New : el uso del New operador crea un nuevo objeto y llama a 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 según dónde se declara. Private | Friend | Public Private | Friend | Public define el nivel de acceso, no el alcance .

Para más información, ver:

Arrays

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 la 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 deducen 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

Se ha creado la matriz, pero no los objetos Foo en ella.

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 crearse o crear instancias.

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

Obtienes 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 un Type colección:

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 resultará en un NRE, porque la lista de barList solo se declara, no se barList una instancia. La creación de una instancia de Foo no creará también una instancia de la lista 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, consulte Clase de List(Of T) .

Objetos del proveedor de datos

Trabajar con bases de datos presenta muchas oportunidades para una NullReference porque puede haber muchos objetos ( Command , Connection , Transaction , Dataset , DataTable , DataRows ...) en uso al mismo tiempo. 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, se declaró el objeto ds datos, pero nunca se creó una instancia. El DataAdapter llenará un DataSet existente, no creará uno. En este caso, dado que ds es una variable local, el IDE le advierte que esto podría suceder:

Cuando se declara como una variable de módulo / nivel de 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ó una NullReferenceException datos llamada "Empleado", por lo que se obtiene un NullReferenceException intenta acceder a ella. Otro problema potencial es asumir que habrá Items que pueden no ser así cuando el SQL incluye una cláusula WHERE.

Remedio

Como esto usa una tabla, el uso de 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 afectadas que también se pueden 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

El 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") referencia a una tabla que no existe.

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

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

Véase también la clase DataTable .

Rutas de objeto / anidadas

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

El código solo está probando Items mientras que myFoo y Bar también pueden ser Nothing. El remedio es probar la cadena completa o la ruta de los objetos uno a la vez:

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 "explore" de forma segura el (los) objeto (s) "nivel" a la vez, evaluando myFoo.Bar solo después de (y si) se determina que myFoo 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 'corriente 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 podría no existir.

Controles de interfaz de usuario

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 UI. ListBox1.SelectedItembien puede ser Nothing, por lo que ListBox1.SelectedItem.ToStringdará lugar a 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 "no puede hacer referencia al miembro no estático". Por lo tanto, hasta cierto punto, esta es una situación solo de VB. También es complejo porque puede dar lugar a una falla en cascada.

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
  • El Array contendrá cinco elementos de Nada.
  • La somevarasignación resultará en una NRE inmediata porque Nothing no tiene una .Textpropiedad

Hacer referencia a los elementos de la matriz más adelante resultará en 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 adelante cuando su código intente utilizar 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 su evento Sub Newo Form Loadevento 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

Tenga en cuenta que esto se aplica a todas y cada una de las referencias de control y componentes que hacen que estas sean ilegales donde se encuentran:

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 no existen. Esto se puede hacer Sub Newmientras 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. Cualquier control que se encuentre en un control de contenedor (como a GroupBoxo Panel) no se encontrará 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 generará una NRE cuando intente hacer referencia a ella.

Estos deberían ser fáciles de encontrar ahora que sabes lo que estás buscando:

"Button2" reside en un Panel

Remedio

En lugar de referencias indirectas por nombre utilizando 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 NullReferenceExceptionpuede resultar en un ' Puede suprimir la advertencia, reemplazando Exit Functioncon Return Nothing, pero eso no resuelve el problema. Cualquier cosa que intente usar el retorno cuando someCondition = Falsese traducirá en un 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 regresar 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...

Mal implementado Try / Catch

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 espera, 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 haga nada, Finallyintente realizar una limpieza, pero como no puede hacer Closeun DataReaderobjeto nulo , los NullReferenceExceptionresultados son nuevos .

Un Catchbloque vacío es el patio del diablo. Este OP estaba desconcertado por la razón por la que obtuvo una NRE en el Finallybloque. En otras situaciones, un vacío Catchpuede resultar en algo mucho más lejano hacia abajo y se puede hacer que pases el tiempo mirando las cosas equivocadas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).

Remedio

No utilice bloques de prueba / captura vacíos: 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 pretenden ocultar excepciones de la persona calificada de forma única 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: 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, puedes probar para Nothing, 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 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 una CheckBoxcon chkNameno se puede encontrar (o existe en una GroupBox), entonces chkhabrá nada y estar intentando hacer referencia a cualquier propiedad dará lugar a una excepción.

Remedio

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

El DataGridView

La 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 lo dgvBooksha hecho AutoGenerateColumns = True, creará las columnas, pero no las nombra, por lo que el código anterior falla cuando las hace referencia por su nombre.

Remedio

Nombra las columnas manualmente, o 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 DataGridViewtiene AllowUserToAddRowscomo True(el valor predeterminado), el Cellsen la fila en blanco / nueva en la parte inferior contendrá Nothing. La mayoría de los intentos de usar los contenidos (por ejemplo, ToString) resultarán en una NRE.

Remedio

Use un For/Eachbucle y pruebe la IsNewRowpropiedad para determinar si es la ú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 utiliza un For nbucle, modifique el recuento de filas o use Exit Forcuando IsNewRowsea ​​verdadero.

Mis.Ajustes (StringCollection)

Bajo ciertas circunstancias, intentar usar un elemento desde el My.Settingscual se StringCollectionpuede generar una NullReference la primera vez que lo 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 está administrando las configuraciones por usted, es razonable esperar que inicialice la colección. Lo hará, pero solo si previamente ha agregado 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 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 / cuando sea necesario:

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

Normalmente, la Settingscolección solo tendrá que inicializarse la primera vez que se ejecute la aplicación. Un remedio alternativo es agregar un valor inicial a su colección en Proyecto -> Configuración | FooBars , guarda el proyecto, luego elimina el valor falso.

Puntos clave

Probablemente te olvidaste del 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


TL; DR: Trate de usar en Html.Partiallugar deRenderpage

Estaba recibiendo Object reference not set to an instance of an objectcuando 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.Partialque empezar era porque Visual Studio a veces arroja líneas onduladas con aspecto de error Html.Partialsi está dentro de un foreachbucle construido de manera diferente , aunque no sea realmente 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 tener este aspecto:

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

Aunque tengo la sensación de que fue porque Visual Studio no leía correctamente los símbolos y los paréntesis.


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 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 esto, 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 extenderá System.Web.UI.Page, se producirá este error.

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


Curiosamente, ninguna de las respuestas en esta página menciona los dos casos de borde, 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 uno NullReferenceo incluso (más frecuente) KeyNotFoundExceptioncuando intenta acceder a una clave desde dos subprocesos simultáneos. La excepción es bastante engañosa en este caso.

Caso de Edge # 2: código inseguro

Si a NullReferenceExceptiones lanzado por unsafecódigo, puede mirar sus variables de puntero y verificarlas IntPtr.Zeroo 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. excepción.

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


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 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ás 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 arroja 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 el objeto a la referencia de esa clase).

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

Puede arreglar NullReferenceException de una manera limpia usando 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 de í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 condicionales nulos


Si consideramos escenarios comunes donde se puede lanzar esta excepción, acceder a las propiedades con el 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

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
}

Simon Mourier dio este ejemplo :

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

donde una conversión de unboxing (conversión) de object (o de una de las clases System.ValueTypeo System.Enum, o de un tipo de interfaz) a un tipo de valor (distinto de Nullable<>) en sí mismo da el NullReferenceException.

En la otra dirección, una conversión de boxeo de a Nullable<>que tiene HasValueigual 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 sucede 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 utiliza cuando se encajonan Nullable<>instancias.


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 haya sido 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á en C # NullReferenceException y Null Parameter .


A NullReferenceExceptionse genera 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 
    

Literalmente, la forma 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 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. Añadir un cuerpo rígido a su objeto con addComponent> Física> cuerpo rígido
    y luego entrar en la secuencia de comandos y escriba rb = GetComponent<Rigidbody>();
    esta línea de código que funciona mejor bajo sus Start()o Awake()funciones.
  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!


Los tipos de referencia se establecen como nulos para indicar que no hacen referencia a ningún objeto. Por lo tanto, si intenta acceder al objeto al que se hace referencia y no hay uno, obtendrá una NullReferenceException .

Por ejemplo:

SqlConnection connection = null;
connection.Open();

Cuando ejecute este código, obtendrá:

System.NullReferenceException: Object reference not set to an instance of an object.

Puedes evitar este error codificando así:

if (connection != null){
    connection.Open();
}

Nota: Para evitar este error, siempre debe inicializar sus objetos antes de intentar hacer algo con ellos.


Otro caso general en el que uno podría recibir esta excepción involucra clases de burla durante la prueba 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 correctamente burlados. En particular, todas las propiedades a las HttpContextque 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.


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

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

Va a tirar NullReferenceExceptionsobre el yeso. 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 ha sido 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 de ASP.NET con el control de calendario:

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

Aquí, SelectedDatede hecho , es una propiedad de DateTimetipo de tipo de Calendarcontrol web, y el enlace podría devolver perfectamente algo nulo. 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 aumentará un NullReferenceExceptionque es bastante difícil de detectar, porque se encuentra en el código generado por ASP.NET que compila bien ...


Si bien lo que provoca un NullReferenceExceptions y enfoques para evitar / corregir tal excepción se han abordado en otras respuestas, lo que muchos programadores no han aprendido todavía cómo es independiente depurar las excepciones durante el desarrollo.

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

Primero, asegúrese de que se detectará el error correcto; consulte ¿Cómo permito que se rompa 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 usarlo Debugger.Break, lo que le pedirá que inicie el depurador.

Ahora, cuando se lanza (o no se maneja) la NullReferenceException, el depurador se detendrá (¿recuerda la regla establecida arriba?) 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 Vigilancia 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 str1fue nulo o si str2fue nulo.

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

Una vez que se ha localizado la excepción de lanzamiento, es generalmente 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. Inspeccionar para expresiones nulas. Inspeccione las expresiones anteriores que podrían haber resultado en tales expresiones nulas. Agregue breakpoints y siga 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 .NET o de terceros, se puede usar Break on Unmanled 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


Si no ha inicializado un tipo de referencia y desea establecer 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 emite una NullReferenceException, es importante conocer la diferencia entre los tipos de valor y los tipos de referencia .

Por lo tanto, si está tratando con tipos de valor , NullReferenceExceptions no puede 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 ser 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

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, si bien he declarado la variable " connection", no apunta a nada. Cuando trato de llamar al miembro " Open", no hay ninguna referencia para que se 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.


Sobre el tema de "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 configurar invariantes de clase , y / o incluso condiciones previas de función / método y postcondiciones en su sistema, mientras se desarrolla.

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 se pondrá en un estado inconsistente). Las condiciones previas significan que los datos dados como entrada a una función / método deben seguir algunas restricciones establecidas y nunca violarlas, y las condiciones posteriores significan que la salida de una 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 sin errores, por lo tanto, el diseño por contrato se verifica en la práctica en el modo de depuración, mientras se deshabilita en las versiones , para maximizar el rendimiento del sistema desarrollado.

De esta manera, puede evitar los NullReferenceExceptioncasos que son el resultado de la violación del conjunto de restricciones. 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 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 un proyecto de Contratos de Código para aplicaciones .NET.

Alternativamente, el diseño por contrato puede ser aplicado usando assertions .

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 .





nullreferenceexception