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


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

Referencia a objeto no establecida como instancia de un objeto.

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


1878


origen


Respuestas:


¿Cual es la causa?

Línea de fondo

Estás tratando de usar algo que es null (o Nothing en VB.NET). Esto significa que o lo configuraste para null, o nunca lo configuras para nada.

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

null puede tener diferentes significados:

  1. Variables de objeto que son sin inicializar y por lo tanto señalar a nada En este caso, si accede a propiedades o métodos de tales objetos, causa un NullReferenceException.
  2. El desarrollador es utilizando null intencionalmente para indicar que no hay un valor significativo disponible. Tenga en cuenta que C # tiene el concepto de tipos de datos anulables para las variables (como las tablas de base de datos pueden tener campos que aceptan nulos) - puede asignar null a ellos para indicar que no hay ningún valor almacenado en ella, por ejemplo int? a = null; donde el signo de interrogación indica que está permitido almacenar nulo en variable a. Puedes verificar eso con if (a.HasValue) {...} o con if (a==null) {...}. Variables anulables, como a este ejemplo, permite acceder al valor a través de a.Value explícitamente, o simplemente como vía normal a.
    Nota que accediendo a ella a través de a.Value arroja un InvalidOperationException en lugar de un NullReferenceException Si a es null - debe hacer el control de antemano, es decir, si tiene otra variable que se puede cancelar int b; entonces deberías hacer asignaciones como if (a.HasValue) { b = a.Value; } o más corto if (a != null) { b = a; }.

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

Más específicamente

El tiempo de ejecución arrojando un NullReferenceException  siempre significa lo mismo: está tratando de usar una referencia, y la referencia no se inicializó (o fue una vez inicializado, pero es no más inicializado).

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

string foo = null;
foo.ToUpper();

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

Depuración

¿Cómo encuentras la fuente de un NullReferenceException? Además de observar la excepción en sí misma, que se lanzará exactamente en el lugar donde se produce, se aplican las reglas generales de depuración en Visual Studio: coloque puntos de corte estratégicos y inspecciona tus variables, colocando el mouse sobre sus nombres, abriendo una ventana (Rápida) Visualización o usando varios paneles de depuración como Locales y Autos.

Si desea saber dónde está o no está establecida la referencia, haga clic derecho en su nombre y seleccione "Buscar todas las referencias". A continuación, puede colocar un punto de interrupción en cada ubicación encontrada y ejecutar su programa con el depurador conectado. Cada vez que el depurador se rompe en un punto de interrupción así, debe determinar si espera que la referencia sea no nula, inspeccionar la variable y verificar que apunta a una instancia cuando lo espera.

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

Ejemplos

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

Genérico

ref1.ref2.ref3.member

Si ref1 o ref2 o ref3 son nulos, entonces obtendrás un NullReferenceException. Si quiere resolver el problema, descubra cuál es nulo reescribiendo la expresión en 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 el User la propiedad podría ser nula, o la Identity la propiedad 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 a

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

Mientras que la new se usa palabra clave, solo crea una nueva instancia de Book, pero no una nueva instancia de Person, entonces el Author la propiedad todavía está 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 a

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

los new Person solo crea una instancia de Person, pero el Books la colección todavía está null. La sintaxis del inicializador de la colección no crea una colección para p1.Books, solo se traduce a p1.Books.Add(...) declaraciones.

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.

Arrays dentados

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

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

Convenciones de mal nombre:

Si nombraste los campos de forma diferente a los locales, te habrás dado cuenta de que nunca has inicializado 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 puede resolverse 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();

Modelos de vista vacía ASP.NET MVC

Si la excepción se produce al hacer referencia a una propiedad de @Model en una vista ASP.NET MVC, 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 del modelo) desde su controlador, la excepción se produce cuando las vistas acceden a él:

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

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

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

Orden de creación de control de WPF y eventos

Los controles WPF se crean durante la llamada a InitializeComponent en el orden en que aparecen en el árbol visual. UN NullReferenceException se planteará en el caso de los controles creados anteriormente con controladores de eventos, etc., que se activan durante InitializeComponent que hacen referencia a los controles de creación tardía.

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 label1. Si comboBox1_SelectionChanged intenta hacer referencia a `label1, aún no habrá sido 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, listado label1 antes de comboBox1, ignorando los problemas de la filosofía del diseño, al menos resolvería la NullReferenceException aquí.

Cast con as

var myThing = someObject as Thing;

Esto no arroja una InvalidCastException pero devuelve un null cuando el lanzamiento falla (y cuando someObject es en sí mismo nulo). Así que ten cuidado de eso.

LINQ FirstOrDefault () y SingleOrDefault ()

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

para cada

foreach lanza cuando intenta iterar colección nula. Usualmente causado por inesperado null resultado de métodos que devuelven colecciones.

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

Ejemplo más realista: seleccione nodos del documento XML. 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

Verificar explícitamente null e ignorar 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);
    }
}

Verificar explícitamente null y proporciona un valor predeterminado.

Los métodos llaman que espera devolver una instancia puede devolver null, por ejemplo, cuando el objeto buscado no puede ser encontrado. Puede optar por devolver un valor predeterminado cuando este sea el caso:

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

Verificar explícitamente null desde llamadas a métodos y lanzar 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;
}

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

Cuando sepa durante el desarrollo que un método puede, pero nunca debe regresar null, puedes usar Debug.Assert() para romper lo más pronto 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 este control no terminará en tu versión de lanzamiento, haciendo que arroje el NullReferenceException de nuevo cuando book == null en tiempo de ejecución en modo de lanzamiento.

Utilizar GetValueOrDefault() para los tipos de valores que se pueden anular 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 coalescente nulo: ?? [C #] o If() [VB].

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

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 matrices (disponible en C # 6 y VB.NET 14):

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

var title = person.Title.ToUpper();

Si la persona no tiene un título, arrojará una excepción porque está tratando de llamar ToUpper en una propiedad con un valor nulo.

En C # 5 y abajo, esto puede protegerse con:

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

Ahora la variable de título será nula en lugar de arrojar 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 nully la llamada a ToUpper no está hecho si person.Title es null.

Por supuesto tú todavía tiene que verificar title para null o utilizar el operador de condición nula junto con el operador de fusión nulo (??) para suministrar 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 arreglos puedes usar ?[i] como sigue:

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 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 la depuración y corrección de derefs nulos en iteradores

C # admite "bloques iteradores" (llamados "generadores" en algunos otros lenguajes populares). Las excepciones de eliminación de referencias nulas 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 resultados en null entonces MakeFrob arrojará Ahora, podrías 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 correr hasta el foreach! La llamada a GetFrobs simplemente devuelve un objeto que cuando iterado ejecutará el bloque iterador.

Al escribir un cheque nulo como este, evita la desreferencia nula, pero mueve la excepción de argumento nulo al punto del 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, crea un método de ayuda privada que tiene la lógica de bloques del iterador y un método de superficie pública que realiza la comprobación nula y devuelve el iterador. Ahora, cuando GetFrobs se llama, la verificación nula ocurre inmediatamente, y luego GetFrobsForReal se ejecuta cuando la secuencia se itera.

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

Una nota sobre desreferencias nulas en código inseguro

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

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

  • desreferenciando un nulo puntero produce la misma excepción que desreferenciar un nulo referencia
  • desreferenciando un puntero no nulo no válido poder producir esa excepción En algunas circunstancias

Para entender por qué es así, es útil comprender cómo .NET produce excepciones de eliminación de referencias nulas 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 memoria tiene banderas establecidas que determinan cómo se puede usar: leer desde, escribir en, ejecutar, etc. los más bajo la página está marcada como "producir un error si alguna vez se usó 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 correspondiente almacenamiento de memoria hace que el sistema operativo produzca un error. El tiempo de ejecución .NET luego detecta este error y lo convierte en la excepción de eliminación de referencias nula.

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

¿Qué hay del segundo punto? Desreferencia alguna El puntero no válido que se encuentra en la página más baja de la memoria virtual causa el mismo error del sistema operativo y, por lo tanto, la misma excepción.

¿Por qué esto tiene sentido? Bueno, supongamos que tenemos una estructura que contiene dos entradas, y un puntero no administrado igual a nulo. Si intentamos eliminar la referencia del 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, esta es una desreferencia nula porque estamos llegando a esa dirección vía el nulo.

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


2107



Excepción de NullReference: Visual Basic

los NullReference Exception para Visual Basic no es diferente de la de DO#. Después de todo, ambos informan la misma excepción definida en .NET Framework que ambos usan. Causas únicas de Visual Basic son raras (quizás solo una).

Esta respuesta utilizará términos, sintaxis y contexto de Visual Basic. Los ejemplos utilizados provienen de una gran cantidad de preguntas anteriores sobre desbordamiento de pila. Esto es para maximizar la relevancia usando el clases de situaciones que a menudo se ven en los mensajes. También se proporciona una explicación un poco más para aquellos que puedan necesitarla. Un ejemplo similar al tuyo es muy Probablemente mencionado aquí.

Nota:

  1. Esto está basado en conceptos: no hay un código para pegar en su proyecto. Está destinado a ayudarlo a comprender qué causa un NullReferenceException (NRE), cómo encontrarlo, cómo solucionarlo y cómo evitarlo. Un NRE puede ser causado 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á tratando de usar un objeto que no se ha inicializado. Esto se reduce a uno de estos:

  • Tu codigo declarado una variable de objeto, pero no lo hizo inicializar (crear una instancia o 'instanciado' eso)
  • Algo que su código asumió que inicializaría un objeto, no lo hizo
  • Posiblemente, otro código invalidó prematuramente un objeto que aún 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 cualquier bloque Try / Catch del código relevante, especialmente aquellos donde no hay nada en el bloque Catch. Esto hará que su código se cuelgue cuando intente usar un objeto que es Nothing. Esto es lo que quieres porque identificará el exacto ubicación del problema, y ​​le permiten identificar el objeto que lo causa.

UN MsgBox en la captura que muestra Error while... será de poca ayuda. Este método también conduce a muy mal 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 puedes usar el Locals Window (Depurar -> Windows -> Locales) para examinar tus objetos.

Una vez que sepa qué 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 / Crear una instancia

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

El problema es ese Dim no crea un CashRegister objeto; solo declara una variable llamada reg de ese tipo. Declarando una variable de objeto y la creación de un ejemplo son dos cosas diferentes

Remedio

los New El operador a menudo se puede usar 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 adelante:

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

Nota: No haga utilizar Dim de nuevo en un procedimiento, incluido el constructor (Sub New)

Private reg As CashRegister
'...

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

Esto creará un local variable, reg, que existe solo en ese contexto (sub). los reg variable con nivel de módulo Scope que usarás en cualquier lugar que quede Nothing.

Perdiendo el New operador es la causa # 1 de NullReference Exceptions visto en las preguntas de desbordamiento de pila revisadas.

Visual Basic intenta borrar el proceso repetidamente usando New: Utilizando el New El operador crea un nuevo objeto y llamadas Sub New - el constructor - donde su objeto puede realizar cualquier otra inicialización.

Para ser claro, Dim (o Private) solamente declara una variable y su Type. los Alcance de la variable, ya sea que exista para todo el módulo / clase o sea local para un procedimiento, está determinada por dónde es declarado. Private | Friend | Public define el nivel de acceso, no 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 Option Infer, el As <Type> y New los elementos 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

La matriz ha sido creada, pero el Foolos objetos en ella no tienen.

Remedio

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

Usando un 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 se deben crear instancias o crear instancias.

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

Obtiene la misma excepción por la misma razón: myList solo fue declarado, 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 utiliza 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 un NRE, porque barList solo se declara, no se crea una instancia. Creando una instancia de Foo tampoco creará una instancia de la interna barList. Pudo haber sido la intención de hacer esto en el constructor:

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

Como antes, esto es incorrecto:

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

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


Objetos 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 a la vez. Nota: No importa qué proveedor de datos esté utilizando: MySQL, SQL Server, OleDB, etc. conceptos son lo mismo.

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, el ds Se declaró el objeto del conjunto de datos, pero nunca se creó una instancia. los DataAdapter llenará un existente DataSet, no crear uno En este caso, desde ds es una variable local, el IDE te 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 en sentido ascendente. No ignores 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 hubo DataTable llamado "Empleado" creado, entonces NullReferenceException resultados tratando de acceder a ella. Otro problema potencial es suponer que habrá Items que puede no ser así cuando el SQL incluye una cláusula WHERE.

Remedio

Como esto usa una tabla, usando Tables(0) evitará errores de ortografía Examinando 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 puede ser probado:

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

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

los Remedio es lo mismo, haga referencia a la tabla por índice:

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

Ver también Clase DataTable.


Rutas de objetos / anidados

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

El código solo está probando Items mientras tanto myFoo y Bar también puede ser Nada. los remedio es probar toda la cadena o camino de los objetos de a uno por 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 el primero False condición se encuentra. Esto permite que el código 'taladre' de forma segura en el 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 cuando se codifican objetos complejos:

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

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

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

Aquí, myWebBrowser o Document podría ser Nada o el formfld1 elemento puede 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.SelectedItem bien podría ser Nothing, asi que ListBox1.SelectedItem.ToString dará como resultado un NRE.

Remedio

Valide los datos antes de usarlos (también use Option Strict y parámetros de 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...


Visual Basic Forms

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 un NRE. En C #, dependiendo de cómo esté codificado, el IDE informará que Controls no existe en el contexto actual, o "no se puede hacer referencia al miembro no estático". Entonces, hasta cierto punto, esta es una situación solo de VB. También es complejo porque puede provocar una cascada de fallas.

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

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

Hacer referencia a los elementos de la matriz más tarde dará como resultado un NRE. Si haces esto en Form_Load, debido a una extraña falla, el IDE podría no informa la excepción cuando sucede. La excepción aparecerá luego cuando tu código intenta usar la matriz. Esta "excepción silenciosa" es detallado en esta publicación. Para nuestros propósitos, la clave es que cuando ocurre algo catastrófico al crear una forma (Sub New o Form Load evento), las excepciones pueden no ser reportadas, el código sale del procedimiento y solo muestra el formulario.

Como no hay otro código en su Sub New o Form Load evento se ejecutará después de la NRE, muchas otras cosas puede 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 que las hacen ilegales donde están:

Public Class Form1

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

Remedio parcial

Es curioso que VB no proporcione una advertencia, pero el remedio es declarar los contenedores a nivel de formulario, pero inicializar ellos en el controlador de eventos de carga de formulario cuando los controles hacer existe. Esto se puede hacer en Sub New siempre y cuando tu código esté después del InitializeComponent llamada:

' 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

El código de la matriz puede no estar fuera de peligro todavía. Cualquier control que esté en un control de contenedor (como un GroupBox o Panel) no se encontrará en Me.Controls; estarán en la colección Controls de ese Panel o GroupBox. Tampoco se devuelve un control cuando el nombre del control está mal escrito ("TeStBox2") En esos casos, Nothing volverá a almacenarse en esos elementos de la matriz y se generará un NRE cuando intente hacer referencia a él.

Estos deberían ser fáciles de encontrar ahora que sabes lo que estás buscando: VS shows you the error of your ways

"Button2" reside en un Panel

Remedio

En lugar de referencias indirectas por nombre usando el formulario Controlscolección, 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 donde el IDE te advertirá que 'no todas las rutas devuelven un valor y una NullReferenceException puede resultar'. Puede suprimir la advertencia, reemplazando Exit Function con Return Nothing, pero eso no resuelve el problema. Cualquier cosa que intente usar el retorno cuando someCondition = False dará como resultado un NRE:

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

Remedio

Reemplazar Exit Function en la función con Return bList. Volviendo un vacío  List no es lo mismo que regresar Nothing. Si existe la posibilidad de que un objeto devuelto pueda ser Nothing, prueba antes de usarlo:

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

Pobremente implementado Try / Catch

Un Try / Catch mal implementado puede ocultar dónde está el problema y dar como resultado 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 creó como se esperaba, pero también demuestra la utilidad del contador de un vacío Catch.

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

Un vacío Catch bloque es el patio del diablo. Este OP estaba desconcertado por qué estaba recibiendo un NRE en el Finally bloquear. En otras situaciones, un vacío Catch puede dar como resultado que algo mucho más aguas abajo se vuelva loco y haga que pases un tiempo mirando las cosas incorrectas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).

Remedio

No use bloques vacíos Try / Catch: deje que el código se bloquee para que pueda a) identificar la causa b) identificar la ubicación yc) aplicar un remedio adecuado. Los bloques Try / Catch no están destinados a ocultar excepciones de la persona calificada de forma exclusiva 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
        ...

los IsDBNull función se utiliza para probar si una valor igual System.DBNull: Desde MSDN:

El valor de 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 nada, luego por 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 un CheckBox con chkName no se puede encontrar (o existe en un GroupBox), entonces chk será Nada e intentar hacer referencia a cualquier propiedad dará como resultado una excepción.

Remedio

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

The DataGridView

La DGV tiene algunas peculiaridades vistas 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 nombra, por lo que el código anterior falla cuando hace referencia a ellas por su nombre.

Remedio

Nombre las columnas de forma manual, o referencia por índice:

dgvBooks.Columns(0).Visible = True

Ejemplo 2 - Cuidado con 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 tu DataGridView tiene AllowUserToAddRows como True (por defecto), el Cells en la fila en blanco / nueva en la parte inferior todos contendrán Nothing. La mayoría de los intentos de usar los contenidos (por ejemplo, ToString) dará como resultado un NRE.

Remedio

Usar una For/Each bucle y prueba el IsNewRow propiedad para determinar si es esa última fila. Esto funciona ya sea AllowUserToAddRows es cierto o no

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

Si usas un For n bucle, modificar el recuento de filas o el uso Exit For cuando IsNewRow es verdad.


My.Settings (StringCollection)

Bajo ciertas circunstancias, tratando de usar un elemento de My.Settings el cual es un StringCollection puede dar como resultado una NullReference la primera vez que la usa. La solución es la misma, pero no tan obvia. Considerar:

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

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

Remedio

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

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

Típicamente, el Settings la colección solo deberá 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, guarde el proyecto, luego elimine el valor falso.


Puntos clave

Probablemente olvidaste el New operador.

o

Algo que asumió que funcionaría sin problemas 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


273



Otro escenario es cuando lanzas un objeto nulo en un tipo de valor. Por ejemplo, el código a continuación:

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

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

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

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

Aquí, SelectedDate es de hecho una propiedad de DateTime tipo - del Calendar El tipo de control web y el enlace podrían devolver algo nulo. El Generador de ASP.NET implícito creará una pieza de código que será equivalente al código de conversión anterior. Y esto levantará un NullReferenceException eso es bastante difícil de detectar, porque se encuentra en el código generado ASP.NET que compila bien ...


217



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

SqlConnection connection = null;
connection.Open();

Eso arrojará el error porque mientras he declarado la variable "connection", no apunta a nada. Cuando trato de llamar al miembro"Open", no hay ninguna referencia para resolver, y lanzará el error.

Para evitar este error:

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

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


146



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

Para evitar el error, los objetos que podrían ser nulos deben probarse 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
}

135



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

Está tratando de 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 cualquier objeto que exista en el montón.

Nunca asignó algo a la variable, nunca creó una instancia del valor asignado a la variable, o establece la variable igual a Nothing/null manualmente, o llamó a una función que establece la variable a Nothing/null para ti.


90



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

Por ejemplo:

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

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

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

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

Más información está en C # NullReferenceException y parámetro nulo.


76



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

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 lanza una NullReferenceException, es importante saber la diferencia entre tipos de valor y tipos de referencia.

Entonces, si estás lidiando con tipos de valor, NullReferenceExceptions puede no ocurrir. Aunque debe mantenerse alerta cuando se trata de tipos de referencia!

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

Tipos de referencia (estos deben estar marcados):

  • dinámica
  • objeto
  • cuerda

Tipos de valor (simplemente puede ignorar estos):

  • Tipos numéricos
  • Tipos integrales
  • Tipos de punto flotante
  • decimal
  • bool
  • Estructuras definidas por el usuario

72



Otro caso donde NullReferenceExceptions puede suceder es el uso (incorrecto) de la as operador:

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; un Car no se puede convertir / convertir a un Book. Cuando este lanzamiento falla, as devoluciones null. Utilizando mybook después de esto causa un NullReferenceException.

En general, debes usar un molde o as, como sigue:

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

ComicBook cb = (ComicBook)specificBook;

Si no está seguro del tipo, pero quiere tratar usarlo como un tipo específico, luego usar as:

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

65