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?
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?
Respuestas:
Está intentando usar algo que es null
(o Nothing
en VB.NET). Esto significa que lo configuró null
o nunca lo configuró para nada.
Como cualquier otra cosa, null
se pasa. Si es null
en el método "A", podría ser que el método "B" pasó una null
de método "A".
null
puede tener diferentes significados:
NullReferenceException
.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 variables (como las tablas de la base de datos pueden tener campos anulables); puede asignarlos null
para indicar que no hay ningún valor almacenado en él, por ejemplo, int? a = null;
donde el signo de interrogación indica que está permitido almacenar nulo en variable a
. Puede verificar eso con if (a.HasValue) {...}
o con if (a==null) {...}
. Las variables anulables, como a
este ejemplo, permiten acceder al valor a través de forma a.Value
explícita, o de manera normal a través de a
. a.Value
arroja un en InvalidOperationException
lugar de un NullReferenceException
if a
esnull
- debe hacer la verificación de antemano, es decir, si tiene otra variable anulable int b;
, debe hacer asignaciones como if (a.HasValue) { b = a.Value; }
o más cortas if (a != null) { b = a; }
.El resto de este artículo entra en más detalles y muestra errores que muchos programadores a menudo cometen y que pueden conducir a una NullReferenceException
.
La runtime
lanzar una NullReferenceException
siempre significa lo mismo: usted está tratando de utilizar una referencia, y la referencia no se ha inicializado (o fue una vez inicializado, sino que está ya no inicializado).
Esto significa que la referencia es null
, y no puede acceder a los miembros (como los métodos) a través de una null
referencia. El caso más simple:
string foo = null;
foo.ToUpper();
Esto arrojará un NullReferenceException
en la segunda línea porque no puede llamar al método de instancia ToUpper()
en una string
referencia que apunta null
.
¿Cómo encuentras la fuente de un NullReferenceException
? Además de mirar la excepción en sí, que se lanzará exactamente en el lugar donde ocurre, se aplican las reglas generales de depuración en Visual Studio: coloque puntos de interrupción estratégicos e inspeccione sus variables , ya sea colocando el mouse sobre sus nombres, abriendo un ( Rápido) Mire la ventana o use los diversos paneles de depuración como Locales y Autos.
Si desea averiguar dónde se establece o no la referencia, haga clic con el botón derecho en su nombre y seleccione "Buscar todas las referencias". Luego puede colocar un punto de interrupción en cada ubicación encontrada y ejecutar su programa con el depurador adjunto. Cada vez que el depurador se interrumpe en dicho punto de interrupción, debe determinar si espera que la referencia no sea nula, inspeccionar la variable y verificar que apunta a una instancia cuando lo espera.
Siguiendo el flujo del programa de esta manera, puede encontrar la ubicación donde la instancia no debe ser nula y por qué no está configurada correctamente.
Algunos escenarios comunes donde se puede lanzar la excepción:
ref1.ref2.ref3.member
Si ref1 o ref2 o ref3 es nulo, obtendrá un NullReferenceException
. Si desea resolver el problema, descubra cuál es nulo reescribiendo la expresión a su equivalente más simple:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Específicamente, en HttpContext.Current.User.Identity.Name
, HttpContext.Current
podría ser nulo, o la User
propiedad podría ser nula, o la Identity
propiedad podría ser nula.
public class Person
{
public int Age { get; set; }
}
public class Book
{
public Person Author { get; set; }
}
public class Example
{
public void Foo()
{
Book b1 = new Book();
int authorAge = b1.Author.Age; // You never initialized the Author property.
// there is no Person to get an Age from.
}
}
Si desea evitar la referencia nula secundaria (Persona), puede inicializarla en el constructor del objeto primario (Libro).
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 new
se usa la palabra clave, solo crea una nueva instancia de Book
, pero no una nueva instancia de Person
, por lo que Author
la propiedad sigue siendo null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
La colección anidada se Initializers
comporta igual:
Person p1 = new Person
{
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Esto se traduce en
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
El new Person
único crea una instancia de Person
, pero la Books
colección sigue siendo null
. La Initializer
sintaxis de la colección no crea una colección p1.Books
, solo se traduce en las p1.Books.Add(...)
declaraciones.
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
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.
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.
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
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.
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
public class Form1 {cliente de cliente privado;
private void Form1_Load(object sender, EventArgs e)
{
Customer customer = new Customer();
customer.Name = "John";
}
private void Button_Click(object sender, EventArgs e)
{
MessageBox.Show(customer.Name);
}
}
Esto se puede resolver siguiendo la convención para prefijar campos con un guión bajo:
private Customer _customer;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
Si la excepción ocurre cuando se hace referencia a una propiedad de @Model
en un ASP.NET MVC View
, debe comprender que Model
se establece en su método de acción, cuando return
ve. Cuando devuelve un modelo vacío (o propiedad de modelo) desde su controlador, la excepción ocurre cuando las vistas acceden a él:
// Controller
public class Restaurant:Controller
{
public ActionResult Search()
{
return View(); // Forgot the provide a Model here.
}
}
// Razor view
@foreach (var restaurantSearch in Model.RestaurantSearch) // Throws.
{
}
<p>@Model.somePropertyName</p> <!-- Also throws -->
WPF
Los controles se crean durante la llamada a InitializeComponent
en el orden en que aparecen en el árbol visual. A se NullReferenceException
generará en el caso de controles creados con controladores de eventos, etc., que se activan durante los InitializeComponent
cuales se hace referencia a los controles creados tarde.
Por ejemplo :
<Grid>
<!-- Combobox declared first -->
<ComboBox Name="comboBox1"
Margin="10"
SelectedIndex="0"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox>
<!-- Label declared later -->
<Label Name="label1"
Content="Label"
Margin="10" />
</Grid>
Aquí comboBox1
se crea antes 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, enumerar label1
antes comboBox1
, ignorar los problemas de la filosofía del diseño, al menos resolvería NullReferenceException
aquí).
as
var myThing = someObject as Thing;
Esto no arroja un InvalidCastException
pero devuelve un null
cuando falla el lanzamiento (y cuando someObject
es nulo). Así que ten cuidado con eso.
FirstOrDefault()
ySingleOrDefault()
Las versiones simples First()
y Single()
lanzan excepciones cuando no hay nada. Las versiones "OrDefault" devuelven nulo en ese caso. Así que ten cuidado con eso.
foreach
arroja cuando intenta iterar colección nula. Generalmente causado por un null
resultado inesperado de métodos que devuelven colecciones.
List<int> list = null;
foreach(var v in list) { } // exception
Ejemplo más realista: seleccione nodos del documento XML. Se lanzará si no se encuentran nodos, pero la depuración inicial muestra que todas las propiedades son válidas:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
e ignore los valores nulos.Si espera que la referencia a veces sea nula, puede verificarla null
antes de acceder a los miembros de la instancia:
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
y proporcione un valor predeterminado.Los métodos de llamada que espera devolver pueden devolver una instancia null
, por ejemplo, cuando no se puede encontrar el objeto que se busca. Puede elegir devolver un valor predeterminado cuando este sea el caso:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
llamadas de método y arroje una excepción personalizada.También puede lanzar una excepción personalizada, solo para atraparla en el código de llamada:
string GetCategory(string bookTitle)
{
var book = library.FindBook(bookTitle); // This may return null
if (book == null)
throw new BookNotFoundException(bookTitle); // Your custom exception
return book.Category;
}
Debug.Assert
si un valor nunca debería ser null
, para detectar el problema antes de que ocurra la excepción.Cuando sabe durante el desarrollo que un método puede, pero nunca debería regresar null
, puede usarlo Debug.Assert()
para interrumpirlo tan pronto como sea posible:
string GetTitle(int knownBookID)
{
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn't return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
Aunque esta verificación no terminará en su versión de lanzamiento , lo que provocará que se lance NullReferenceException
nuevamente book == null
en tiempo de ejecución en modo de lanzamiento.
GetValueOrDefault()
para los nullable
tipos de valor para proporcionar un valor predeterminado cuando lo sean null
.DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
??
[C #] o If()
[VB].La abreviatura para proporcionar un valor predeterminado cuando null
se encuentra un:
IService CreateService(ILogger log, Int32? frobPowerLevel)
{
var serviceImpl = new MyService(log ?? NullLog.Instance);
// Note that the above "GetValueOrDefault()" can also be rewritten to use
// the coalesce operator:
serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}
?.
o ?[x]
para matrices (disponible en C # 6 y VB.NET 14):Esto a veces también se llama el operador de navegación segura o Elvis (después de su forma). Si la expresión en el lado izquierdo del operador es nula, entonces no se evaluará el lado derecho, y en su lugar se devolverá nulo. Eso significa casos como este:
var title = person.Title.ToUpper();
Si la persona no tiene un título, esto generará una excepción porque está intentando invocar ToUpper
una propiedad con un valor nulo.
A C# 5
continuación, esto se puede proteger con:
var title = person.Title == null ? null : person.Title.ToUpper();
Ahora la variable de título será nula en lugar de lanzar una excepción. C # 6 introduce una sintaxis más corta para esto:
var title = person.Title?.ToUpper();
Esto dará como resultado la variable de título null
, y la llamada a ToUpper
no se realiza si person.Title
es así null
.
Por supuesto, aún tiene que verificar title
si es nulo o utilizar el operador de condición nula junto con el operador de fusión nulo ( ??
) para proporcionar un valor predeterminado:
// regular null check
int titleLength = 0;
if (title != null)
titleLength = title.Length; // If title is null, this would throw NullReferenceException
// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;
Del mismo modo, para las matrices puede usar ?[i]
lo siguiente:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Esto hará lo siguiente: Si myIntArray
es nulo, la expresión devuelve nulo y puede verificarlo con seguridad. Si contiene una matriz, hará lo mismo que:
elem = myIntArray[i];
y devuelve el i<sup>th</sup>
elemento.
Introducido en el C# 8
contexto nulo y los tipos de referencia anulables realizan un análisis estático de las variables y proporciona una advertencia del compilador si un valor puede ser potencialmente nulo o si se ha establecido en nulo. Los tipos de referencia anulables permiten que los tipos sean explícitamente nulos.
El contexto de anulación anulable y el contexto de advertencia anulable se pueden configurar para un proyecto utilizando el Nullable
elemento en su csproj
archivo. Este elemento configura cómo el compilador interpreta la nulabilidad de los tipos y qué advertencias se generan. Las configuraciones válidas son:
Se observa un tipo de referencia anulable utilizando la misma sintaxis que los tipos de valores anulables: a ?
se agrega al tipo de la variable.
C#
admite "bloques iteradores" (llamados "generadores" en algunos otros idiomas populares). Las excepciones de anulación de referencia pueden ser particularmente difíciles de depurar en bloques iteradores debido a la ejecución diferida:
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
...
FrobFactory factory = whatever;
IEnumerable<Frobs> frobs = GetFrobs();
...
foreach(Frob frob in frobs) { ... }
Si whatever
como resultado null
entonces MakeFrob
a tirar. Ahora, puede pensar que lo correcto es esto:
// DON'T DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
if (f == null)
throw new ArgumentNullException("f", "factory must not be null");
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
¿Por qué está mal esto? ¡Porque el bloque iterador no se ejecuta realmente hasta que foreach
! La llamada a GetFrobs
simplemente devuelve un objeto que cuando se itera ejecutará el bloque iterador.
Al escribir una verificación nula como esta, evita la desreferencia nula, pero mueve la excepción de argumento nulo al punto de la iteración , no al punto de la llamada , y eso es muy confuso para depurar .
La solución correcta es:
// DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
// No yields in a public method that throws!
if (f == null)
throw new ArgumentNullException("f", "factory must not be null");
return GetFrobsForReal(f, count);
}
private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
{
// Yields in a private method
Debug.Assert(f != null);
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
Es decir, cree un método auxiliar privado que tenga la lógica de bloqueo del iterador y un método de superficie pública que haga la comprobación nula y devuelva el iterador. Ahora, cuando GetFrobs
se llama, la verificación nula ocurre de inmediato y luego se GetFrobsForReal
ejecuta cuando la secuencia se repite.
Si examina la fuente de referencia para LINQ
Objetos, verá que esta técnica se utiliza en todo momento. Es un poco más torpe escribir, pero hace que la depuración de errores de nulidad sea mucho más fácil. Optimice su código para la conveniencia de la persona que llama, no la conveniencia del autor .
C#
tiene un modo "inseguro" que, como su nombre lo indica, es extremadamente peligroso porque no se aplican los mecanismos de seguridad normales que proporcionan seguridad de memoria y de tipo. No debe escribir código inseguro a menos que tenga un conocimiento profundo y profundo de cómo funciona la memoria .
En modo inseguro, debe tener en cuenta dos hechos importantes:
Para entender por qué es así, es útil entender cómo .NET produce excepciones de anulación de referencia en primer lugar. (Estos detalles se aplican a .NET que se ejecuta en Windows; otros sistemas operativos utilizan mecanismos similares).
La memoria está virtualizada en Windows
; cada proceso obtiene un espacio de memoria virtual de muchas "páginas" de memoria que son rastreadas por el sistema operativo. Cada página de memoria tiene marcas establecidas que determinan cómo se puede usar: leer, escribir, ejecutar, etc. La página más baja está marcada como "producir un error si alguna vez se usa de alguna manera".
Tanto un puntero nulo como una referencia nula C#
se representan internamente como el número cero, por lo que cualquier intento de desreferenciarlo en su almacenamiento de memoria correspondiente hace que el sistema operativo produzca un error. El tiempo de ejecución .NET luego detecta este error y lo convierte en la excepción de anulación de referencia nula.
Es por eso que desreferenciar tanto un puntero nulo como una referencia nula produce la misma excepción.
¿Qué pasa con el segundo punto? Anular la referencia a cualquier puntero no válido que se encuentre en la página más baja de la memoria virtual provoca el mismo error del sistema operativo y, por lo tanto, la misma excepción.
¿Por qué esto tiene sentido? Bueno, supongamos que tenemos una estructura que contiene dos entradas y un puntero no administrado igual a nulo. Si intentamos desreferenciar el segundo int en la estructura, CLR
no intentaremos acceder al almacenamiento en la ubicación cero; accederá al almacenamiento en la ubicación cuatro. Pero lógicamente, esta es una anulación de referencia nula porque estamos llegando a esa dirección a través de la nula.
Si está trabajando con código inseguro y obtiene una excepción de anulación de referencia nula, solo tenga en cuenta que el puntero infractor no necesita ser nulo. Puede ser cualquier ubicación en la página más baja, y se producirá esta excepción.
new Book { Author = { Age = 45 } };
¿Cómo funciona la inicialización interna incluso ... No puedo pensar en una situación en la que el init interno funcione alguna vez, sin embargo, compila e intellisense funciona ... A menos que sea para estructuras?
El NullReference Exception
para Visual Basic no es diferente del de C # . Después de todo, ambos informan la misma excepción definida en .NET Framework que ambos usan. Las causas exclusivas de Visual Basic son raras (quizás solo una).
Esta respuesta usará términos, sintaxis y contexto de Visual Basic. Los ejemplos utilizados provienen de una gran cantidad de preguntas anteriores de Stack Overflow. Esto es para maximizar la relevancia mediante el uso de los tipos de situaciones que a menudo se ven en las publicaciones. También se proporciona un poco más de explicación para aquellos que lo necesiten. Un ejemplo similar al suyo es muy probable que aparezca aquí.
Nota:
NullReferenceException
(NRE), cómo encontrarla, cómo solucionarla y cómo evitarla. Una NRE puede ser causada de muchas maneras, por lo que es poco probable que sea su único encuentro.El mensaje "Objeto no establecido en una instancia de Object" significa que está intentando utilizar un objeto que no se ha inicializado. Esto se reduce a uno de estos:
Dado que el problema es una referencia a un objeto Nothing
, la respuesta es examinarlos para averiguar cuál. Luego determine por qué no se inicializa. Mantenga el mouse sobre las diversas variables y Visual Studio (VS) mostrará sus valores, el culpable será Nothing
.
También debe eliminar los bloques Try / Catch del código relevante, especialmente aquellos en los que no hay nada en el bloque Catch. Esto hará que su código se bloquee cuando intente usar un objeto que es Nothing
. Esto es lo que desea porque identificará la ubicación exacta del problema y le permitirá identificar el objeto que lo causó.
A MsgBox
en la captura que muestra Error while...
será de poca ayuda. Este método también lleva a preguntas de desbordamiento de pila muy malas , porque no puede describir la excepción real, el objeto involucrado o incluso la línea de código donde sucede.
También puede usar Locals Window
( Depurar -> Windows -> Locales ) para examinar sus objetos.
Una vez que sepa cuál y dónde está el problema, generalmente es bastante fácil de solucionar y más rápido que publicar una nueva pregunta.
Ver también:
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 a menudo se puede usar para crear la instancia cuando la declaras:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Cuando solo es apropiado crear la instancia más tarde:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Nota: No lo use 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 localreg
, que existe solo en ese contexto (sub). La reg
variable con nivel de módulo Scope
que usará en cualquier otro lugar permanece Nothing
.
La falta del
New
operador es la causa número 1 de loNullReference Exceptions
visto en las preguntas de desbordamiento de pila revisadas.Visual Basic intenta aclarar el proceso repetidamente utilizando
New
: El uso delNew
operador crea un nuevo objeto y llamaSub New
al constructor, donde su objeto puede realizar cualquier otra inicialización.
Para ser claros, Dim
(o Private
) solo declara una variable y su Type
. El alcance de la variable, ya sea que exista para todo el módulo / clase o sea local para un procedimiento, se determina por el lugar donde se declara. Private | Friend | Public
define el nivel de acceso, no el alcance .
Para más información, ver:
Las matrices también deben ser instanciadas:
Private arr as String()
Esta matriz solo ha sido declarada, no creada. Hay varias formas de inicializar una matriz:
Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}
' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}
Nota: a partir de VS 2010, al inicializar una matriz local utilizando un literal y Option Infer
, los elementos As <Type>
y New
son opcionales:
Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}
El tipo de datos y el tamaño de la matriz se infieren de los datos que se asignan. Las declaraciones de nivel de clase / módulo aún requieren As <Type>
con Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Ejemplo: matriz de objetos de clase
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
La matriz se ha creado, pero los Foo
objetos que contiene no.
Remedio
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Usar a List(Of T)
hará que sea bastante difícil tener un elemento sin un objeto válido:
Dim FooList As New List(Of Foo) ' List created, but it is empty
Dim f As Foo ' Temporary variable for the loop
For i As Integer = 0 To 5
f = New Foo() ' Foo instance created
f.Bar = i * 10
FooList.Add(f) ' Foo object added to list
Next
Para más información, ver:
Las colecciones .NET (de las cuales hay muchas variedades - Listas, Diccionario, etc.) también deben ser instanciadas o creadas.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
Obtiene la misma excepción por el mismo motivo: myList
solo se declaró, pero no se creó ninguna instancia. El remedio es el mismo:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
Un descuido común es una clase que usa una colección Type
:
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
Cualquiera de los procedimientos dará como resultado una NRE, porque barList
solo se declara, no se instancia. Crear una instancia de Foo
no también creará una instancia de lo interno barList
. Puede haber sido la intención de hacer esto en el constructor:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Como antes, esto es incorrecto:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Para más información, ver List(Of T)
Clase .
Trabajar con bases de datos presenta muchas oportunidades para un NullReference porque no puede haber muchos objetos ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) en el uso de una sola vez. Nota: No importa qué proveedor de datos esté utilizando (MySQL, SQL Server, OleDB, etc.), los conceptos son los mismos.
Ejemplo 1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer
con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count ' Error
Como antes, ds
se declaró el objeto Dataset, pero nunca se creó una instancia. El DataAdapter
llenará un existente DataSet
, 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 nivel de módulo / clase, como parece ser el caso con
, el compilador no puede saber si el objeto fue creado por un procedimiento ascendente. No ignore las advertencias.
Remedio
Dim ds As New DataSet
Ejemplo 2
ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")
txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)
Un error tipográfico es un problema aquí: Employees
vs Employee
. No se DataTable
creó un nombre de "Empleado", por lo que los NullReferenceException
resultados intentaron acceder a él. Otro problema potencial es asumir que habrá lo Items
que puede no ser así cuando el SQL incluye una cláusula WHERE.
Remedio
Como esto usa una tabla, el uso Tables(0)
evitará errores ortográficos. El examen Rows.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
afectados que también se puede probar:
If da.Fill(ds, "Employees") > 0 Then...
Ejemplo 3
Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)
If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then
La DataAdapter
proporcionará TableNames
como se muestra en el ejemplo anterior, pero no es así nombres de análisis sintáctico de la tabla o base de datos SQL. Como resultado, hace ds.Tables("TICKET_RESERVATION")
referencia a una tabla inexistente.
El remedio es el mismo, consulte la tabla por índice:
If ds.Tables(0).Rows.Count > 0 Then
Ver también la clase DataTable .
If myFoo.Bar.Items IsNot Nothing Then
...
El código solo está probando Items
mientras ambos myFoo
y Bar
también puede ser Nothing. El remedio es probar la cadena o ruta completa de los objetos, uno a la vez:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
es importante. Las pruebas posteriores no se realizarán una vez False
que se encuentre la primera condición. Esto permite que el código 'se desplace' de forma segura en el (los) objeto (s) un 'nivel' a la vez, evaluando myFoo.Bar
solo después de (y si) myFoo
se determina que es válido. Las cadenas o rutas de objetos pueden ser bastante largas al codificar objetos complejos:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
No es posible hacer referencia a nada 'aguas abajo' de un 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.
Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
& "FROM Invoice where invoice_no = '" & _
Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
Me.expiry.Text & "'", con)
Entre otras cosas, este código no anticipa que el usuario no haya seleccionado algo en uno o más controles de IU. ListBox1.SelectedItem
bien puede ser Nothing
, por ListBox1.SelectedItem.ToString
lo que resultará en una NRE.
Remedio
Valide los datos antes de usarlos (también use Option Strict
y 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...
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 Controls
no existe en el contexto actual o que "no puede hacer referencia a un miembro no estático". Entonces, hasta cierto punto, esta es una situación de solo VB. También es complejo porque puede provocar una cascada de fallas.
Las matrices y colecciones no se pueden inicializar de esta manera. Este código de inicialización se ejecutará antes de que el constructor cree el Form
o el Controls
. Como resultado:
somevar
asignación dará como resultado una NRE inmediata porque Nothing no tiene una .Text
propiedadHacer referencia a elementos de la matriz más adelante dará como resultado una NRE. Si hace esto Form_Load
, debido a un error extraño, el IDE puede no informar la excepción cuando ocurra. La excepción aparecerá más tarde cuando su código intente usar la matriz. Esta "excepción silenciosa" se detalla en esta publicación . Para nuestros propósitos, la clave es que cuando ocurre algo catastrófico al crear un formulario ( Sub New
o Form Load
evento), las excepciones pueden no ser reportadas, el código sale del procedimiento y solo muestra el formulario.
Dado que ningún otro código en tu Sub New
o Form Load
evento se desarrollará después de la NRE, un gran número de otras cosas se pueden dejar sin inicializar.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Tenga en cuenta que esto se aplica a todas y cada una de las referencias de control y componentes que las hacen ilegales donde están:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Remedio parcial
Es curioso que VB no proporciona una advertencia, pero el remedio es declarar los contenedores en el nivel de la forma, pero inicializar en controlador de eventos de carga de formulario cuando los controles hacen existir. Esto se puede hacer Sub New
siempre que su código esté después de la 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
Es posible que el código de matriz aún no esté fuera de peligro. Los controles que están en un control de contenedor (como a GroupBox
o Panel
) no se encontrarán en Me.Controls
; estarán en la colección de Controles de ese Panel o GroupBox. Tampoco se devolverá un control cuando el nombre del control esté mal escrito ( "TeStBox2"
). En tales casos, Nothing
se almacenará nuevamente en esos elementos de la matriz y se producirá un NRE cuando intente hacer referencia a él.
Estos deberían ser fáciles de encontrar ahora que sabe lo que está buscando:
"Button2" reside en un Panel
Remedio
En lugar de referencias indirectas por nombre usando la Controls
colecció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...})
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 NullReferenceException
pueden 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 una NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Remedio
Reemplazar Exit Function
en la función con Return bList
. Devolver un vacío List
no es lo mismo que devolver Nothing
. Si existe la posibilidad de que se pueda devolver un objeto Nothing
, pruebe antes de usarlo:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Un Try / Catch mal implementado puede ocultar dónde está el problema y generar otros nuevos:
Dim dr As SqlDataReader
Try
Dim lnk As LinkButton = TryCast(sender, LinkButton)
Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username") = eid
sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='" & eid & "'"
If connection.State <> ConnectionState.Open Then
connection.Open()
End If
command = New SqlCommand(sqlQry, connection)
'More code fooing and barring
dr = command.ExecuteReader()
If dr.Read() Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))
...
End If
mpe.Show()
Catch
Finally
command.Dispose()
dr.Close() ' <-- NRE
connection.Close()
End Try
Este es un caso de un objeto que no se crea como se esperaba, pero también demuestra la utilidad del contador de un vacío Catch
.
Hay una coma adicional en el SQL (después de 'mailaddress') que da como resultado una excepción en .ExecuteReader
. Después de Catch
que no hace nada, Finally
intenta realizar la limpieza, pero como no puede Close
un DataReader
objeto nulo , se NullReferenceException
obtienen resultados completamente nuevos .
Un Catch
bloque vacío es el patio del diablo. Este OP estaba desconcertado por qué estaba obteniendo una NRE en el Finally
bloque. En otras situaciones, un vacío Catch
puede dar lugar a que algo mucho más alejado se vuelva loco y hacer que pase tiempo mirando las cosas incorrectas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).
Remedio
No use bloques vacíos Try / Catch: deje que el código se bloquee para que pueda a) identificar la causa b) identificar la ubicación yc) aplicar un remedio adecuado. Los bloques Try / Catch no están destinados a ocultar excepciones de la persona calificada para solucionarlos: el desarrollador.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
La IsDBNull
función se usa para probar si un valor es igual a System.DBNull
: Desde MSDN:
El valor System.DBNull indica que el Objeto representa datos faltantes o inexistentes. DBNull no es lo mismo que Nothing, lo que indica que una variable aún no se ha inicializado.
Remedio
If row.Cells(0) IsNot Nothing Then ...
Como antes, puede probar para Nada, luego para un valor específico:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Ejemplo 2
Dim getFoo = (From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
If Not IsDBNull(getFoo) Then
If IsDBNull(getFoo.user_id) Then
txtFirst.Text = getFoo.first_name
Else
...
FirstOrDefault
devuelve el primer elemento o el valor predeterminado, que es Nothing
para tipos de referencia y nunca DBNull
:
If getFoo IsNot Nothing Then...
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
Si no se puede encontrar un CheckBox
with chkName
(o existe en a GroupBox
), entonces chk
será Nothing e intentar hacer referencia a cualquier propiedad dará como resultado una excepción.
Remedio
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
El DGV tiene algunas peculiaridades que se ven periódicamente:
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
Si dgvBooks
es AutoGenerateColumns = True
así, creará las columnas, pero no las nombrará, por lo que el código anterior falla cuando hace referencia a ellas por su nombre.
Remedio
Nombre las columnas manualmente, o haga referencia por índice:
dgvBooks.Columns(0).Visible = True
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 DataGridView
tiene AllowUserToAddRows
como True
(el valor predeterminado), todo Cells
en la fila en blanco / nueva en la parte inferior contendrá Nothing
. La mayoría de los intentos de usar el contenido (por ejemplo ToString
) dará como resultado una NRE.
Remedio
Use un For/Each
bucle y pruebe la IsNewRow
propiedad para determinar si es esa última fila. Esto funciona si AllowUserToAddRows
es cierto o no:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Si usa un For n
bucle, modifique el recuento de filas o use Exit For
cuándo IsNewRow
es verdadero.
Bajo ciertas circunstancias, tratar de usar un elemento del My.Settings
cual es un StringCollection
puede resultar en una NullReference la primera vez que la use. La solución es la misma, pero no tan obvia. Considerar:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Dado que VB administra la configuración por usted, es razonable esperar que inicialice la recopilación. Lo hará, pero solo si ha agregado previamente una entrada inicial a la colección (en el editor de Configuración). Como la colección se inicializa (aparentemente) cuando se agrega un elemento, permanece Nothing
cuando no hay elementos en el editor de Configuración para agregar.
Remedio
Inicialice la colección de configuraciones en el Load
controlador de eventos del formulario , si es necesario:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Por lo general, la Settings
colección solo deberá inicializarse la primera vez que se ejecute la aplicación. Una solución alternativa es agregar un valor inicial a su colección en Proyecto -> Configuración | FooBars , guarde el proyecto, luego elimine el valor falso.
Probablemente olvidaste el New
operador.
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).
Otro escenario es cuando convierte un objeto nulo en un tipo de valor . Por ejemplo, el siguiente código:
object o = null;
DateTime d = (DateTime)o;
Lanzará un NullReferenceException
sobre el elenco. Parece bastante obvio en el ejemplo anterior, pero esto puede suceder en escenarios intrincados más "de enlace tardío" en los que el objeto nulo ha sido devuelto por algún código que no es de su propiedad, y el reparto es generado, por ejemplo, por algún sistema automático.
Un ejemplo de esto es este fragmento de enlace ASP.NET simple con el control Calendar:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Aquí, SelectedDate
de hecho , es una propiedad, de DateTime
tipo, del Calendar
tipo Control web, y el enlace podría devolver algo nulo perfectamente. El Generador ASP.NET implícito creará un fragmento de código que será equivalente al código de transmisión anterior. Y esto generará un problema NullReferenceException
que es bastante difícil de detectar, ya que se encuentra en el código generado por ASP.NET que se compila bien ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Significa que la variable en cuestión no apunta a nada. Podría generar esto así:
SqlConnection connection = null;
connection.Open();
Eso arrojará el error porque aunque he declarado la variable " connection
", no apunta a nada. Cuando intento llamar al miembro " Open
", no hay ninguna referencia para resolverlo y arrojará el error.
Para evitar este error:
object == null
.La herramienta Resharper de JetBrains identificará cada lugar en su código que tenga la posibilidad de un error de referencia nulo, lo que le permite realizar una verificación nula. Este error es la fuente número uno de errores, en mi humilde opinión.
Significa que su código utilizó una variable de referencia de objeto que se estableció en nulo (es decir, no hizo referencia a una instancia de objeto real).
Para evitar el error, los objetos que podrían ser nulos deben ser probados para nulo antes de ser utilizados.
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
Tenga en cuenta que, independientemente del escenario, la causa es siempre la misma en .NET:
Está intentando utilizar una variable de referencia cuyo valor es
Nothing
/null
. Cuando el valor esNothing
/null
para la variable de referencia, eso significa que en realidad no contiene una referencia a una instancia de ningún objeto que exista en el montón.Nunca asignó algo a la variable, nunca creó una instancia del valor asignado a la variable, o configuró la variable igual
Nothing
/null
manualmente, o llamó a una función que establezca la variable enNothing
/null
para usted.
Un ejemplo de esta excepción lanzada es: cuando intenta verificar algo, eso es nulo.
Por ejemplo:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
El tiempo de ejecución de .NET generará una NullReferenceException cuando intente realizar una acción en algo que no se haya instanciado, es decir, el código anterior.
En comparación con una excepción ArgumentNullException que generalmente se lanza como una medida defensiva si un método espera que lo que se le pasa no sea nulo.
Más información está en C # NullReferenceException y Null Parameter .
Actualización C # 8.0, 2019: tipos de referencia anulables
C # 8.0 introduce tipos de referencia anulables y tipos de referencia no anulables . Tipos de referencia por lo que sólo admiten nulos deben ser evaluados para evitar una NullReferenceException .
Si no ha inicializado un tipo de referencia y desea establecer o leer una de sus propiedades, arrojará una NullReferenceException .
Ejemplo:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Simplemente puede evitar esto comprobando si la variable no es nula:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Para comprender completamente por qué se produce una NullReferenceException, es importante conocer la diferencia entre los tipos de valor y [tipos de referencia] [3].
Por lo tanto, si se trata de tipos de valores , NullReferenceExceptions no puede ocurrir. ¡Aunque debe mantenerse alerta al tratar con tipos de referencia !
Solo los tipos de referencia, como sugiere el nombre, pueden contener referencias o apuntar literalmente a nada (o 'nulo'). Mientras que los tipos de valor siempre contienen un valor.
Tipos de referencia (estos deben ser verificados):
Tipos de valor (simplemente puede ignorar estos):
Otro caso en el que NullReferenceExceptions
puede suceder es el uso (incorrecto) del 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; a Car
no se puede convertir / lanzar a a Book
. Cuando este lanzamiento falla, as
regresa null
. Usar mybook
después de esto causa a NullReferenceException
.
En general, debe usar un yeso o as
, de la siguiente manera:
Si espera que la conversión de tipos siempre tenga éxito (es decir, sabe cuál debe ser el objeto antes de tiempo), entonces debe usar un molde:
ComicBook cb = (ComicBook)specificBook;
Si no está seguro del tipo, pero desea intentar usarlo como un tipo específico, use as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Está utilizando el objeto que contiene la referencia de valor nulo. Entonces está dando una excepción nula. En el ejemplo, el valor de la cadena es nulo y, al verificar su longitud, se produjo la excepción.
Ejemplo:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
El error de excepción es:
Excepción no controlada:
System.NullReferenceException: referencia de objeto no establecida en una instancia de un objeto. en Program.Main ()
Si bien lo que causa un NullReferenceExceptions y los enfoques para evitar / solucionar dicha excepción se han abordado en otras respuestas, lo que muchos programadores aún no han aprendido es cómo depurar de forma independiente dichas excepciones durante el desarrollo.
En Visual Studio, esto suele ser fácil gracias al Visual Studio Debugger .
Primero, asegúrese de detectar el error correcto: consulte ¿Cómo permito romper en 'System.NullReferenceException' en VS2010? Nota 1
Luego, comience con la depuración (F5) o adjunte [el depurador VS] al proceso en ejecución . En ocasiones puede ser útil usar Debugger.Break
, lo que le pedirá que inicie el depurador.
Ahora, cuando se lanza la NullReferenceException (o no se controla), el depurador se detendrá (¿recuerda la regla establecida anteriormente?) En la línea en la que ocurrió la excepción. A veces el error será fácil de detectar.
Por ejemplo, en la siguiente línea, el único código que puede causar la excepción es si se myString
evalúa como nulo. Esto se puede verificar mirando la Ventana de Observación o ejecutando expresiones en la Ventana Inmediata .
var x = myString.Trim();
En casos más avanzados, como los siguientes, deberá usar una de las técnicas anteriores (Watch o Windows Inmediato) para inspeccionar las expresiones para determinar si str1
era nulo o si str2
era nulo.
var x = str1.Trim() + str2.Trim();
Una vez que se ha localizado la excepción, generalmente es trivial razonar hacia atrás para descubrir dónde se introdujo [incorrectamente] el valor nulo:
Tómese el tiempo necesario para comprender la causa de la excepción. Inspeccione las expresiones nulas. Inspeccione las expresiones anteriores que podrían haber resultado en tales expresiones nulas. Agregue puntos de interrupción y avance por el programa según corresponda. Usa el depurador.
1 Si Break on Throws es demasiado agresivo y el depurador se detiene en un NPE en la biblioteca .NET o de terceros, se puede usar Break on User-Unledled para limitar las excepciones detectadas. Además, VS2012 presenta Just My Code, que recomiendo habilitar también.
Si está depurando con Just My Code habilitado, el comportamiento es ligeramente diferente. Con Just My Code habilitado, el depurador ignora las excepciones de Common Language Runtime (CLR) de primera oportunidad que se arrojan fuera de My Code y no pasan por My Code
Simon Mourier dio este ejemplo :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
donde una conversión de unboxing (cast) de object
(o de una de las clases System.ValueType
o System.Enum
, o de un tipo de interfaz) a un tipo de valor (que no seaNullable<>
) en sí mismo proporciona el NullReferenceException
.
En la otra dirección, una conversión de boxeo de una Nullable<>
que tieneHasValue
igual false
a un tipo de referencia, puede dar una null
referencia que luego puede conducir a a NullReferenceException
. El ejemplo clásico es:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
A veces el boxeo ocurre de otra manera. Por ejemplo con este método de extensión no genérico:
public static void MyExtension(this object x)
{
x.ToString();
}
el siguiente código será problemático:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Estos casos surgen debido a las reglas especiales que el tiempo de ejecución usa al boxear Nullable<>
instancias.
Agregar un caso cuando el nombre de la clase para la entidad utilizada en el marco de la entidad es el mismo que el nombre de la clase para un archivo de código subyacente de formulario web.
Supongamos que tiene un formulario web Contact.aspx cuya clase de código subyacente es Contact y tiene un nombre de entidad Contact.
Luego, el siguiente código arrojará una NullReferenceException cuando llame a context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
En aras de la integridad de la clase DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
y clase de entidad de contacto. A veces, las clases de entidad son clases parciales, por lo que también puede ampliarlas en otros archivos.
public partial class Contact
{
public string Name {get; set;}
}
El error ocurre cuando la entidad y la clase codebehind están en el mismo espacio de nombres. Para solucionar esto, cambie el nombre de la clase de entidad o la clase de código subyacente para Contact.aspx.
Razón Todavía no estoy seguro del motivo. Pero cada vez que cualquiera de la clase de entidad extenderá System.Web.UI.Page, se produce este error.
Para discusión, eche un vistazo a NullReferenceException en DbContext.saveChanges ()
Otro caso general en el que uno podría recibir esta excepción implica burlarse de las clases durante las pruebas unitarias. Independientemente del marco de simulación que se utilice, debe asegurarse de que todos los niveles apropiados de la jerarquía de clases se burlen correctamente. En particular, todas las propiedades deHttpContext
deben burlar que hace referencia el código bajo prueba.
Consulte " NullReferenceException lanzada al probar AuthorizationAttribute personalizado " para obtener un ejemplo algo detallado.
Tengo una perspectiva diferente para responder esto. Este tipo de respuestas "¿qué más puedo hacer para evitarlo? "
Cuando se trabaja en diferentes capas , por ejemplo en una aplicación MVC, un controlador necesita servicios para llamar a las operaciones comerciales. En tales escenarios, el Contenedor de inyección de dependencias se puede utilizar para inicializar los servicios para evitar la NullReferenceException . Eso significa que no necesita preocuparse por verificar nulos y simplemente llamar a los servicios desde el controlador como si siempre estuvieran disponibles (e inicializados) como un singleton o un prototipo.
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don't need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}
En cuanto a "qué debo hacer al respecto" , puede haber muchas respuestas.
Una forma más "formal" de prevenir tales condiciones de error durante el desarrollo es aplicar el diseño por contrato en su código. Esto significa que necesita establecer invariantes de clase , y / o incluso precondiciones y postcondiciones de función / método en su sistema, durante el desarrollo.
En resumen, los invariantes de clase aseguran que habrá algunas restricciones en su clase que no serán violadas en el uso normal (y, por lo tanto, la clase no entrará en un estado inconsistente). Las condiciones previas significan que los datos proporcionados como entrada para una función / método deben seguir algunas restricciones establecidas y nunca violarlas, y las condiciones posteriores significan que una salida de función / método debe seguir las restricciones establecidas nuevamente sin violarlas nunca. Las condiciones del contrato nunca deben violarse durante la ejecución de un programa libre de errores, por lo tanto, el diseño por contrato se verifica en la práctica en modo de depuración, mientras se desactiva en las versiones , para maximizar el rendimiento del sistema desarrollado.
De esta manera, puede evitar NullReferenceException
casos que son el resultado de la violación de las restricciones establecidas. Por ejemplo, si usa una propiedad de objeto X
en una clase y luego intenta invocar uno de sus métodos y X
tiene un valor nulo, esto conducirá a NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Pero si establece "la propiedad X nunca debe tener un valor nulo" como condición previa del método, puede evitar el escenario descrito anteriormente:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Por esta causa, el proyecto de contratos de código existe para aplicaciones .NET.
Alternativamente, el diseño por contrato se puede aplicar utilizando aserciones .
ACTUALIZACIÓN: Vale la pena mencionar que el término fue acuñado por Bertrand Meyer en relación con su diseño del lenguaje de programación Eiffel .
Se NullReferenceException
genera A cuando intentamos acceder a las Propiedades de un objeto nulo o cuando un valor de cadena se vacía y estamos intentando acceder a métodos de cadena.
Por ejemplo:
Cuando se accede a un método de cadena de una cadena vacía:
string str = string.Empty;
str.ToLower(); // throw null reference exception
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
String.Empty.ToLower()
no lanzará una excepción de referencia nula. Representa una cadena real, aunque vacía (es decir ""
). Como esto tiene un objeto al que invocar ToLower()
, no tendría sentido lanzar una excepción de referencia nula allí.
TL; DR: intente usar en Html.Partial
lugar deRenderpage
Obtuve Object reference not set to an instance of an object
cuando traté de representar una Vista dentro de una Vista enviándole un Modelo, como este:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
La depuración mostró que el modelo era Nulo dentro de MyOtherView. Hasta que lo cambié a:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Y funcionó.
Además, la razón por la que no tuve Html.Partial
que comenzar fue porque Visual Studio a veces arroja líneas onduladas con aspecto de error Html.Partial
si está dentro de un foreach
bucle de construcción diferente , aunque en realidad no es un error:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
Pero pude ejecutar la aplicación sin problemas con este "error". Pude deshacerme del error cambiando la estructura del foreach
bucle para que se vea así:
@foreach(var M in MyEntities){
...
}
Aunque tengo la sensación de que fue porque Visual Studio estaba leyendo mal los símbolos y los corchetes.
Html.Partial
, no@Html.Partial
Null
), así que sabía que el error estaba en cómo estaba enviando el Modelo.
¿Qué puedes hacer al respecto?
Aquí hay muchas buenas respuestas que explican qué es una referencia nula y cómo depurarla. Pero hay muy poco sobre cómo prevenir el problema o al menos facilitar su detección.
Verificar argumentos
Por ejemplo, los métodos pueden verificar los diferentes argumentos para ver si son nulos y arrojar un ArgumentNullException
, una excepción obviamente creada para este propósito exacto.
El constructor para el ArgumentNullException
par toma el nombre del parámetro y un mensaje como argumentos para que pueda decirle al desarrollador exactamente cuál es el problema.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Usar herramientas
También hay varias bibliotecas que pueden ayudar. "Resharper", por ejemplo, puede proporcionarle advertencias mientras escribe código, especialmente si usa su atributo: NotNullAttribute
Hay "Contratos de código de Microsoft" donde usa una sintaxis como la Contract.Requires(obj != null)
que le da tiempo de ejecución y compilación de verificación: Introducción de contratos de código .
También hay "PostSharp" que le permitirá usar atributos como este:
public void DoSometing([NotNull] obj)
Al hacer eso y hacer que PostSharp forme parte de su proceso de compilación obj
, se verificará que no es nulo en tiempo de ejecución. Ver: verificación nula PostSharp
Solución de código simple
O siempre puede codificar su propio enfoque utilizando un código antiguo simple. Por ejemplo, aquí hay una estructura que puede usar para capturar referencias nulas. Se basa en el mismo concepto que Nullable<T>
:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Usaría una forma muy similar a la misma que usaría Nullable<T>
, excepto con el objetivo de lograr exactamente lo contrario: no permitir null
. Aquí hay unos ejemplos:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
está implícitamente emitido hacia y desde T
para que pueda usarlo en cualquier lugar donde lo necesite. Por ejemplo, puede pasar un Person
objeto a un método que tome un NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Como puede ver arriba, como con nulable, accedería al valor subyacente a través de la Value
propiedad. Alternativamente, puede usar una conversión explícita o implícita, puede ver un ejemplo con el valor de retorno a continuación:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
O incluso puede usarlo cuando el método simplemente regrese T
(en este caso Person
) haciendo un lanzamiento. Por ejemplo, al siguiente código le gustaría el código anterior:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combinar con extensión
Combine NotNull<T>
con un método de extensión y puede cubrir incluso más situaciones. Aquí hay un ejemplo de cómo puede verse el método de extensión:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
Y aquí hay un ejemplo de cómo podría usarse:
var person = GetPerson().NotNull();
GitHub
Para su referencia, hice que el código anterior esté disponible en GitHub, puede encontrarlo en:
https://github.com/luisperezphd/NotNull
Característica relacionada del lenguaje
C # 6.0 introdujo el "operador nulo-condicional" que ayuda un poco con esto. Con esta función, puede hacer referencia a objetos anidados y, si alguno de ellos es null
la expresión completa, regresa null
.
Esto reduce la cantidad de comprobaciones nulas que tiene que hacer en algunos casos. La sintaxis es poner un signo de interrogación antes de cada punto. Tome el siguiente código, por ejemplo:
var address = country?.State?.County?.City;
Imagine que country
es un objeto de tipo Country
que tiene una propiedad llamada State
y así sucesivamente. Si country
, State
, County
, o City
es null
entonces address will be
nula . Therefore you only have to check whether
dirección is
null`.
Es una gran característica, pero le brinda menos información. No hace obvio cuál de los 4 es nulo.
¿Incorporado como Nullable?
C # tiene una buena abreviatura para Nullable<T>
, puede hacer que algo sea anulable poniendo un signo de interrogación después del tipo de esta manera int?
.
Sería bueno si C # tenido algo así como la NotNull<T>
estructura anterior y tenía una taquigrafía similares, tal vez el signo de exclamación para que usted podría escribir algo como (!): public void WriteName(Person! person)
.
Curiosamente, ninguna de las respuestas en esta página menciona los dos casos extremos, espero que a nadie le importe si los agrego:
Los diccionarios genéricos en .NET no son seguros para subprocesos y a veces pueden arrojar un NullReference
o incluso (más frecuente) unKeyNotFoundException
cuando intenta acceder a una clave desde dos subprocesos simultáneos. La excepción es bastante engañosa en este caso.
Si el código NullReferenceException
arroja una unsafe
, puede mirar las variables de puntero y verificar siIntPtr.Zero
o algo así. Lo que es lo mismo ("excepción de puntero nulo"), pero en el código inseguro, las variables a menudo se convierten en tipos / matrices de valores, etc., y te golpeas la cabeza contra la pared, preguntándote cómo un tipo de valor puede arrojar esto excepción.
(Por cierto, otra razón para no usar código inseguro a menos que lo necesite)
null
qué manera?
Puede arreglar NullReferenceException de manera limpia utilizando operadores condicional nulo en c # 6 y escribir menos código para manejar las comprobaciones nulas.
Se utiliza para probar nulo antes de realizar una operación de acceso de miembro (?.) O índice (? [).
Ejemplo
var name = p?.Spouse?.FirstName;
es equivalente a:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
El resultado es que el nombre será nulo cuando p sea nulo o cuando p.Spouse sea nulo.
De lo contrario, al nombre de la variable se le asignará el valor de p.Spouse.FirstName.
Para más detalles: Operadores condicional nulo
La línea de error "Referencia de objeto no establecida en una instancia de un objeto" indica que no ha asignado un objeto de instancia a una referencia de objeto y que aún está accediendo a propiedades / métodos de ese objeto.
por ejemplo: supongamos que tiene una clase llamada myClass y contiene una propiedad prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Ahora está accediendo a este prop1 en alguna otra clase, como a continuación:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
la línea anterior arroja un error porque la referencia de la clase myClass se declara pero no se instancia o una instancia del objeto no se asigna a la referencia de esa clase.
Para solucionar esto, debe crear una instancia (asignar objeto a la referencia de esa clase).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
NullReferenceException o la referencia de objeto no establecida en una instancia de un objeto se produce cuando un objeto de la clase que está intentando utilizar no se instancia. Por ejemplo:
Suponga que tiene una clase llamada Estudiante.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Ahora, considere otra clase en la que está tratando de recuperar el nombre completo del alumno.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Como se ve en el código anterior, la declaración Student s - solo declara la variable de tipo Student, tenga en cuenta que la clase Student no se instancia en este punto. Por lo tanto, cuando se ejecuta la instrucción s.GetFullName () , arrojará la NullReferenceException.
Bueno, en términos simples:
Está intentando acceder a un objeto que no está creado o que actualmente no está en la memoria.
Entonces, cómo abordar esto:
Depura y deja que el depurador se rompa ... Te llevará directamente a la variable que está rota ... Ahora tu tarea es simplemente solucionar esto ... Usando la nueva palabra clave en el lugar apropiado.
Si se produce en algunos comandos de la base de datos porque el objeto no está presente, entonces todo lo que necesita hacer es hacer una verificación nula y manejarlo:
if (i == null) {
// Handle this
}
El más difícil ... si el GC ya recolectó el objeto ... Esto generalmente ocurre si está tratando de encontrar un objeto usando cadenas ... Es decir, si lo encuentra por el nombre del objeto, puede suceder que el GC ya pueda lo limpió ... Esto es difícil de encontrar y se convertirá en un gran problema ... Una mejor manera de abordar esto es realizar comprobaciones nulas siempre que sea necesario durante el proceso de desarrollo. Esto te ahorrara mucho tiempo.
Al encontrar por nombre me refiero a que algún marco le permite FIndObjects usando cadenas y el código podría verse así: FindObject ("ObjectName");
Literalmente, la forma más fácil de arreglar una NullReferenceExeption tiene dos formas. Si tiene un GameObject, por ejemplo, con un script adjunto y una variable llamada rb (cuerpo rígido), esta variable comenzará nula cuando inicie el juego.
Es por eso que obtiene una NullReferenceExeption porque la computadora no tiene datos almacenados en esa variable.
Usaré una variable RigidBody como ejemplo.
Podemos agregar datos realmente fácilmente de varias maneras:
rb = GetComponent<Rigidbody>();
Start()
o Awake()
. rb = AddComponent<RigidBody>();
Notas adicionales: Si desea la unidad para agregar un componente a su objeto y puede haber olvidado agregar uno, puede escribir [RequireComponent(typeof(RigidBody))]
arriba de su declaración de clase (el espacio debajo de todos sus usos).
¡Disfruta y diviértete haciendo juegos!
Si consideramos escenarios comunes donde se puede lanzar esta excepción, accedemos a las propiedades dentro del objeto en la parte superior.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
aquí, si la dirección es nula, obtendrá NullReferenceException.
Por lo tanto, como práctica, siempre debemos usar la verificación nula, antes de acceder a las propiedades de dichos objetos (especialmente en genéricos)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Esto es básicamente una excepción de referencia nula . Como Microsoft Unidos-
Se produce una excepción NullReferenceException cuando intenta acceder a un miembro de un tipo cuyo valor es nulo.
Eso significa que si algún miembro que no tiene ningún valor y estamos haciendo que ese miembro realice cierta tarea, el sistema indudablemente arrojará un mensaje y dirá:
"Oye, espera, ese miembro no tiene valores, por lo que no puede realizar la tarea que le estás entregando".
La excepción en sí dice que se está refiriendo algo pero cuyo valor no se está estableciendo. Esto denota que solo ocurre mientras se usan tipos de referencia, ya que los tipos de Valor no son anulables.
NullReferenceException no ocurrirá si estamos utilizando miembros de tipo Value.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
El código anterior muestra una cadena simple que se asigna con un valor nulo .
Ahora, cuando intento imprimir la longitud de la cadena str , recibo un mensaje de excepción no controlada del tipo 'System.NullReferenceException' porque el miembro str apunta a nulo y no puede haber ninguna longitud nula.
' NullReferenceException ' también ocurre cuando olvidamos instanciar un tipo de referencia.
Supongamos que tengo una clase y un método miembro. No he instanciado mi clase, sino que solo he nombrado mi clase. Ahora, si trato de usar el método, el compilador arrojará un error o emitirá una advertencia (dependiendo del compilador).
class Program
{
static void Main(string[] args)
{
MyClass1 obj;
obj.foo(); //Use of unassigned local variable 'obj'
}
}
public class MyClass1
{
internal void foo()
{
Console.WriteLine("hello from foo");
}
}
El compilador para el código anterior genera un error de que la variable obj no está asignada, lo que significa que nuestra variable tiene valores nulos o nada. El compilador para el código anterior genera un error de que la variable obj no está asignada, lo que significa que nuestra variable tiene valores nulos o nada.
NullReferenceException surge debido a nuestra culpa por no verificar el valor del objeto. A menudo dejamos los valores del objeto sin marcar en el desarrollo del código.
También surge cuando olvidamos instanciar nuestros objetos. El uso de métodos, propiedades, colecciones, etc. que pueden devolver o establecer valores nulos también puede ser la causa de esta excepción.
Hay varias formas y métodos para evitar esta reconocida excepción:
Comprobación explícita: debemos cumplir con la tradición de comprobar los objetos, propiedades, métodos, matrices y colecciones si son nulos. Esto se puede implementar simplemente usando declaraciones condicionales como if-else if-else, etc.
Manejo de excepciones: una de las formas importantes de gestionar esta excepción. Usando simples bloques try-catch-finally podemos controlar esta excepción y también mantener un registro de la misma. Esto puede ser muy útil cuando su aplicación está en etapa de producción.
Operadores nulos: el operador de fusión nula y los operadores condicionales nulos también se pueden usar a la vez que se configuran valores para objetos, variables, propiedades y campos.
Depurador: para los desarrolladores, tenemos el gran arma de la depuración con nosotros. Si nos enfrentamos a NullReferenceException durante el desarrollo, podemos usar el depurador para llegar al origen de la excepción.
Método incorporado: los métodos del sistema como GetValueOrDefault (), IsNullOrWhiteSpace () e IsNullorEmpty () comprueban nulos y asignan el valor predeterminado si hay un valor nulo.
Ya hay muchas buenas respuestas aquí. También puede consultar una descripción más detallada con ejemplos en mi blog .
Espero que esto ayude también!
Si uno recibe este mensaje durante el guardado o la compilación de la compilación, simplemente cierre todos los archivos y luego abra cualquier archivo para compilar y guardar.
Para mí, la razón era que había cambiado el nombre del archivo y el archivo antiguo todavía estaba abierto.