NullReferenceException
It is one of the exceptions that raises the most questions. What does it mean NullReferenceException
and how can it be fixed?
For the NullReferenceException
in C# and .Net, see What is a NullReferenceException and how to fix it?
The one
NullReferenceException
in Visual Basic is no different than the one in C# . After all, they both report the same exception defined in the .Net Framework that both languages are based on. The causes that may be unique to Visual Basic are few (perhaps only one).This answer will use Visual Basic terms, syntax, and context. The examples used are taken from a large number of old questions on Stack Overflow. In this way, its relevance is maximized, using the kind of situations that often arise in posts. Some more explanations are also attached for those who may need them. An example similar to yours is very likely to be found here.
Grades:
NullReferenceException
NRE, how to find it, how to fix it, and how to avoid it. An NRE can have many causes so don't expect to find all of them here.Basic Meaning
The message "Object reference not set to an instance of an object" means that you are trying to use an object that has not been initialized. This can be narrowed down to one of these causes:
Finding the cause
Assuming that the problem is an object reference that is
Nothing
, the answer is to examine the objects to find which one is the problem, and then determine why it is not initialized. Hold your mouse cursor over the variables and Visual Studio (VS) will show you their values - the culprit will beNothing
.You should also remove any Try/Catch blocks from the relevant parts of your code, especially those that have an empty Catch block. This will cause your code to fail when it tries to use an object that is
Nothing
. This is what you want , as this will pinpoint the exact location of the problem, allowing you to identify which object is causing it.An
MsgBox
in the Catch block that showsError en...
is very unhelpful. This method of catching exceptions also causes very bad questions on Stack Overflow, since you can't describe the actual exception, what object is causing it, and not even the line of code where it happened.You can also use the window
Variables Locales
( Debug -> Windows -> Locals ) to examine your objects.Once you know what the problem is and where it is, it's usually very easy to fix and faster than adding a new question.
See also:
Examples and solutions
Class Objects / Creating an Instance
The problem is that
Dim
it doesn't create an object of typeRegistradora
; it just declares a named variablereg
of that Type. Declaring an object variable and creating an instance of it are two different things.Solution
The operator
New
is the one normally used to create the instance when you declare the object:When the instance should be created later:
Note: Do not use
Dim
again in a procedure, including the constructor (Sub New
):This will create a local variable ,
reg
, which exists only in this (sub) context. The variablereg
that you have asámbito
the module and that you will use everywhere else remains asNothing
.To make this clear,
Dim
(oPrivate
) just declares a variable and itsType
( type ). The scope of the variable - whether it exists for the entire module/class or whether it is local to a procedure - is determined by where it is declared.Private | Friend | Public
defines the level of access, not its Scope .For more information, see:
Arrays
Arrays must also be instantiated:
This array has only been declared, not created. There are several ways to initialize an array:
Note: As of VS 2010, when initializing a local array using a literal and
Option Infer
, the elementsAs <Type>
andNew
are optional:The type and size of the array size are inferred from the data that is allocated. Class/Module level declarations still require
As <Type>
withOption Strict
:Example: Array of class objects
The array has been created, but the objects of type
Foo
in it have not.Solution
Using one
List(Of T)
will make it quite difficult to have an element without a valid object:For more information, see:
Lists and Collections
Collections in .NET (of which there are many varieties - Lists, Dictionaries, etc.) must also be instantiated or created.
You get the same exception for the same reason - it
miLista
was just declared, but no instance was created. The solution is the same:A common mistake is a class that uses a
Type
collection type( ) :Both procedures will cause an NRE, because
barList
it was only declared, not instantiated. Creating an instance ofFoo
will not also create an instance of thebarList
inner one. Maybe the intention was to do it in the constructor:As before, this is not correct:
For more information, see Class
List<T>
.Data Provider Objects
Working with databases means there are many opportunities for a NullReferenceException since there can be many objects (
Command
,Connection
,Transaction
,Dataset
,DataTable
,DataRows
....) in use at the same time. Note: It doesn't matter what data provider you use -- MySQL, SQL Server, OleDB, etc. -- the concepts are the same.Example 1
As before, the Dataset
ds
has been declared, but an instance of it has never been created. HeDataAdapter
fills anDataSet
existing one, he does not create one. In this case, since itds
is a local variable, the IDE gives you a warning that this could happen:When declared as a variable at the module/class level, as seems to be the case with
con
, the compiler cannot tell if the object was created by a bottom-up procedure. Don't ignore the warnings.Solution
Example 2
A typo is the problem here:
Empleados
->Empleado
. There is noDataTable
one called "Employee", so oneNullReferenceException
results from trying to access it. Another potential problem is assuming that they will existItems
, which may not be true when the SQL query contains a WHERE clause.Solution
Since only one table is being used in the example, using
Tables(0)
will avoid misspellings. BrowseRows.Count
can also help:Fill
is a function that returns the number ofRows
affected rows( ) that can also be checked:Example 3
The will
DataAdapter
provideTableNames
as seen in the example above, but does not parse the database table names. As a result, itds.Tables("TICKET_RESERVATION")
references a table that does not exist.The solution is the same, reference the table by its index:
See also DataTable class .
Object Paths ( Object Paths ) / Nested ( Nested )
The code is just testing
Items
whilemyFoo
andBar
could also beNothing
. The solution is to try the entire chain or the ture of the objects one at a time:AndAlso
It is important. Subsequent tests will not run once the first condition is metFalse
. This allows code to safely check objects from level to level, evaluatingmyFoo.Bar
only after (and if) it is determined tomyFoo
be valid. Object chains or paths can get quite long when dealing with complex objects:It is also not possible to reference anything below a null object. This also applies to controls:
Here, they could
myWebBrowser
eitherDocument
beNothing
, or the elementformfld1
could not exist.UI Controls
Among other things, this code does not anticipate that the user might not have selected anything in one or more controls.
ListBox1.SelectedItem
could very well beNothing
, so it willListBox1.SelectedItem.ToString
cause an NRE.Solution
Validate the data before using it (it is also recommended to use
Option Strict
and SQL parameters):Alternatively, you could also use
(ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
This is a very common way to obtain an NRE. In C#, depending on how it's programmed, the IDE would report that
Controls
it doesn't exist in the current context, or "Cannot access a non-static member from a static scope." So in a way this is a situation that can only happen in VB. It is also a complex situation, because it can cause a cascading failure.Arrays and collections cannot be initialized this way. This initialization code will be executed before the constructor creates the Form or controls(
Controls
). As a result:Nothing
unaVariable
resultará en una NRE inmediata, porqueNothing
no tiene una propiedad.Text
Referenciar los elementos del array mas tarde resultará en una NRE. Si lo haces en el
Form_Load
, debido a un bug extraño, el IDE podría no reportar la excepción cuando ocurra. La excepción aparecerá mas tarde cuando tu código intent usar el array. Esta "excepción silenciosa" es detallada en este post (en inglés). Para nuestro propósito, la clave es que cuando algo catastrófico ocurre al crear un formulario (Sub New
o eventoForm Load
), las excepciones podrían no reportarse. El flujo sale del procedimiento y simplemente muestra el formulario.Dado que ningún código mas en tu
Sub New
o en tu eventoForm Load
se ejecutará después de la NRE, un montón de otras cosas podrían quedarse sin inicializar.Nota esto aplica para cualquiera y todas las referencias a controles y componentes haciendo esto ilegal donde se encuentre:
Solución parcial
Es curioso que VB no de al menos un aviso, pero la solución es declarar los contenedores a nivel de formulario, pero inicializarles en el evento form load cuando los controles realmente existen. Esto se puede hacer también en
Sub New
siempre y cuando tu código esté después de la llamada aInitializeComponent
:El código del array podría no estar a salvo todavía. Cualquier control que esté en un control contenedor (como un
GroupBox
oPanel
) no se encontrará enMe.Controls
; estarán en la colecciónControls
de ese Panel o GroupBox. Tampoco se devolverá ningun control si su nombre está mal escrito ("TeStBox2"
). En esos casos, en esos elementos del array se almacenaráNothing
y resultará en una NRE cuando intentes referenciarlos.Estos deberían ser fáciles de encontrar ahora que ya sabes lo que estás buscando:
"Button2" está contenido en un
Panel
Solución
En lugar de usar referencias indirectas por nombre usando la colección
Controls
del formulario, usa la referencia del control:Function que devuelve Nothing
Este es un caso donde el IDE mostrará un aviso de que 'no todas las rutas devuelve un valor lo que puede resultar en una
NullReferenceException
'. Puedes suprimir el aviso sustituyendoExit Function
conReturn Nothing
, pero eso no resuelve el problema. Cualquier cosa que intente usar el valor devuelto cuandosomeCondition = False
resultará en una NRE:Solución
Cambia
Exit Function
en la función porReturn bList
. Devolver una lista(List
) vacía no es lo mismo que devolverNothing
. Si existe la posibilidad de que un objeto devuelto pueda serNothing
, compruébalo antes de usarlo:Try/Catch mal implementado
Un Try/Catch mal implementado puede ocultar donde está el problema y provocar como consecuencia otros nuevos:
Este caso es el de un objeto que no ha sido creado como se esperaba, pero también demuestra la "extrema" utilidad de un
Catch
vacío.Hay una coma de más en el SQL (después de 'mailaddress') que causa una excepción en
.ExecuteReader
. Después de queCatch
no haga nada,Finally
intenta hacer limpieza, pero como no puedes cerrar(Close
) unDataReader
nulo, una nuevaNullReferenceException
es lanzada.Un bloque
Catch
vacío es muy peligroso y nada recomendable. Este OP estaba sorprendido intentando entender porqué estaba obteniendo una NRE en el bloqueFinally
. En otras situaciones, unCatch
vacío podría resultar en algo mucho mas grave y hacerte perder mucho tiempo probando cosas equivocadas en el lugar equivocado para encontrar el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo entretenimiento añadido.)Solución
No uses bloques Try/Catch vacios - deja que el código falle para que puedas a) identificar la causa b) indetificar la localización y c) aplicar la solución correcta. Los bloques Try/Catch no se hicieron para ocultar las excepciones de la persona cualificada para solucionarlas - el desarrollador.
DBNull no es lo mismo que Nothing
La función
IsDBNull
se usa para comprobar si un valor es igual queSystem.DBNull
: De MSDN:Solución
Como antes, puedes comprobar primero
Nothing
, y después por un valor específico:Ejemplo 2
FirstOrDefault
devuelve el primer elemento o el valor por defecto, que en el caso de tipos de referencia esNothing
y nuncaDBNull
:Controles
Si un
CheckBox
conchkName
no se encuentra (o existe en unGroupBox
), entonceschk
seráNothing
y el intento de referenciar cualquier propiedad resultará en una excepción.Solución
El DataGridView
El DGV tiene algunos "caprichos" que se ven periódicamente:
Si
dgvBooks
tieneAutoGenerateColumns = True
, creará las columnas pero no las pondrá nombre, así que el código de arriba falla cuando trata de referenciarlas por nombre.Solución
Pon nombre a las columnas manualmente, o referéncialas por índice:
Ejemplo 2 — Cuidado con NewRow
Cuando tu
DataGridView
tieneAllowUserToAddRows
aTrue
(pro defecto), lasCells
en la fila vacía/nueva al final contendrán todasNothing
. Los intentos de usar los contenidos de ésta (por ejemplo,ToString
) resultarán en una NRE.Solución
Usa un bucle
For/Each
y pregunta por la propiedadIsNewRow
para determinar si es la última fila. Esto funciona aunqueAllowUserToAddRows
sea true o false:Si usas un bucle
For n
, modifica el contador de filas o usaExit For
cuandoIsNewRow
es true.My.Settings (StringCollection)
Bajo ciertas circunstancias, intentado usar un elemento de
My.Settings
que es unStringCollection
puede resultar en una NullReference la primera vez que lo usas. La solución es la misma, aunque no tan obvia. Considera:Ya que VB está gestionando Settings por ti, es razonable esperar que inicialice la colección. Lo hará, pero solo si previamente has añadido un elemento inicial a la colección (en el editor de Settings). Ya que la colección esta siendo (aparentemente) inicializada cuando un elemento es añadido, permanece a
Nothing
cuando no hay elementos en el editor de Settings para añadir.Solución
Inicializa la colección de settings en el manejador del evento
Load
del formulario, si es necesario:Typically, the collection
Settings
would only need to be initialized the first time the application is run. An alternative solution is to add an initial value to the collection in Project -> Settings | FooBars , save the project, and then remove the false value.Key points
You probably forgot the operator
New
.either
Something you assumed would work perfectly to return an initialized object hasn't.
Don't ignore compiler warnings (never) and use
Option Strict On
(always).MSDN Class NullReferenceException
This answer is a translation of this Stack Overflow answer