vacio - system.nullreferenceexception referencia a objeto no establecida como instancia de un objeto c#
¿Qué es una NullReferenceException y cómo puedo solucionarlo? (30)
¿Cual es la causa?
Línea de fondo
Está intentando usar algo que es null
(o Nothing
en VB.NET). Esto significa que o bien lo configura en null
, o nunca lo establece en nada.
Como cualquier otra cosa, null
se pasa alrededor. Si es null
en el método "A", podría ser que el método "B" pasó un null
al método "A".
null
puede tener diferentes significados:
- Las variables de objeto que están sin inicializar y por lo tanto apuntan a nada. En este caso, si accede a las propiedades o métodos de dichos objetos, se genera una
NullReferenceException
. - El desarrollador está utilizando
null
intencionalmente para indicar que no hay un valor significativo disponible. Tenga en cuenta que C # tiene el concepto de tipos de datos que admiten nulos para las variables (como las tablas de base de datos pueden tener campos que admitennull
): puede asignarles unnull
para indicar que no hay ningún valor almacenado, por ejemplo,int? a = null;
int? a = null;
donde el signo de interrogación indica que está permitido almacenar nulo en la variablea
. Puede verificarlo conif (a.HasValue) {...}
o conif (a==null) {...}
. Las variables anulables, como este ejemplo, permiten acceder al valor a través dea.Value
explícitamente, o simplemente de la forma normal a través dea
.
Tenga en cuenta que acceder a él a través dea.Value
lanza unaInvalidOperationException
lugar de unaNullReferenceException
sia
esnull
: debe hacer la comprobación de antemano, es decir, si tiene otra variableint b;
nullableint b;
entonces deberías hacer asignaciones comoif (a.HasValue) { b = a.Value; }
if (a.HasValue) { b = a.Value; }
o más cortoif (a != null) { b = a; }
if (a != null) { b = a; }
.
El resto de este artículo es más detallado y muestra los errores que muchos programadores suelen cometer, lo que puede generar una NullReferenceException
.
Más específicamente
El tiempo de ejecución al lanzar una NullReferenceException
siempre significa lo mismo: está intentando usar una referencia, y la referencia no se inicializa (o una vez se inicializó, pero ya no se inicializa).
Esto significa que la referencia es null
y no puede acceder a los miembros (como los métodos) a través de una referencia null
. El caso más simple:
string foo = null;
foo.ToUpper();
Esto lanzará una NullReferenceException
en la segunda línea porque no puede llamar al método de instancia ToUpper()
en una referencia de string
apunta a null
.
Depuración
¿Cómo encuentra la fuente de una NullReferenceException
? Además de ver la excepción en sí, que se lanzará exactamente en el lugar donde se produce, se aplican las reglas generales de depuración en Visual Studio: coloque puntos de interrupción estratégicos e inspeccione sus variables , ya sea colocando el mouse sobre sus nombres, abriendo un ( Rápido) Vea la ventana o utilice los diversos paneles de depuración como Locales y Autos.
Si desea saber dónde está o no está establecida la referencia, haga clic con el botón derecho en su nombre y seleccione "Buscar todas las referencias". Luego puede colocar un punto de interrupción en cada ubicación encontrada y ejecutar su programa con el depurador adjunto. Cada vez que el depurador se rompe en tal punto de interrupción, debe determinar si espera que la referencia no sea nula, inspeccionar la variable y verificar que apunta a una instancia cuando espera que lo haga.
Al seguir el flujo del programa de esta manera, puede encontrar la ubicación donde la instancia no debería ser nula y por qué no está configurada correctamente.
Ejemplos
Algunos escenarios comunes donde se puede lanzar la excepción:
Genérico
ref1.ref2.ref3.member
Si ref1 o ref2 o ref3 es nulo, obtendrá una NullReferenceException
. Si desea resolver el problema, descubra cuál es nulo reescribiendo la expresión a su equivalente más simple:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Específicamente, en HttpContext.Current.User.Identity.Name
, HttpContext.Current
podría ser nulo, o la propiedad User
podría ser nula, o la propiedad Identity
podría ser nula.
Indirecto
public class Person {
public int Age { get; set; }
}
public class Book {
public Person Author { get; set; }
}
public class Example {
public void Foo() {
Book b1 = new Book();
int authorAge = b1.Author.Age; // You never initialized the Author property.
// there is no Person to get an Age from.
}
}
Si desea evitar la referencia nula secundaria (Persona), puede inicializarla en el constructor del objeto principal (Libro).
Inicializadores de objetos anidados
Lo mismo se aplica a los inicializadores de objetos anidados:
Book b1 = new Book { Author = { Age = 45 } };
Esto se traduce en
Book b1 = new Book();
b1.Author.Age = 45;
Mientras se usa la new
palabra clave, solo crea una nueva instancia de Book
, pero no una nueva instancia de Person
, por lo que el Author
la propiedad sigue siendo null
.
Inicializadores de colecciones anidadas
public class Person {
public ICollection<Book> Books { get; set; }
}
public class Book {
public string Title { get; set; }
}
Los inicializadores de colección anidados se comportan igual:
Person p1 = new Person {
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Esto se traduce en
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
La new Person
solo crea una instancia de Person
, pero la colección Books
sigue siendo null
. La sintaxis del inicializador de colección no crea una colección para p1.Books
, solo se traduce a las p1.Books.Add(...)
.
Formación
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
Array Elements
Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
// initialized. There is no Person to set the Age for.
Matrices dentadas
long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
// Use array[0] = new long[2]; first.
Colección / Lista / Diccionario
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
Variable de rango (indirecta / diferida)
public class Person {
public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
// on the line above. "p" is null because the
// first element we added to the list is null.
Eventos
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
Malas convenciones de nomenclatura:
Si nombró campos de manera diferente a los locales, es posible que se haya dado cuenta de que nunca inicializó el campo.
public class Form1 {
private Customer customer;
private void Form1_Load(object sender, EventArgs e) {
Customer customer = new Customer();
customer.Name = "John";
}
private void Button_Click(object sender, EventArgs e) {
MessageBox.Show(customer.Name);
}
}
Esto se puede resolver siguiendo la convención para prefijar campos con un guión bajo:
private Customer _customer;
Ciclo de vida de la página ASP.NET:
public partial class Issues_Edit : System.Web.UI.Page
{
protected TestIssue myIssue;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Only called on first load, not when button clicked
myIssue = new TestIssue();
}
}
protected void SaveButton_Click(object sender, EventArgs e)
{
myIssue.Entry = "NullReferenceException here!";
}
}
Valores de sesión de ASP.NET
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
ASP.NET MVC modelos de vista vacía
Si la excepción se produce al hacer referencia a una propiedad de @Model
en una vista MVC de ASP.NET, debe comprender que el Model
se establece en su método de acción cuando return
una vista. Cuando devuelve un modelo vacío (o propiedad de modelo) de su controlador, la excepción se produce cuando las vistas acceden al mismo:
// Controller
public class Restaurant:Controller
{
public ActionResult Search()
{
return View(); // Forgot the provide a Model here.
}
}
// Razor view
@foreach (var restaurantSearch in Model.RestaurantSearch) // Throws.
{
}
<p>@Model.somePropertyName</p> <!-- Also throws -->
WPF Control Creation Order and Events
Los controles WPF se crean durante la llamada a InitializeComponent
en el orden en que aparecen en el árbol visual. Se generará una NullReferenceException
en el caso de los controles creados anteriormente con controladores de eventos, etc., que se activan durante InitializeComponent
que hacen referencia a los controles creados tardíamente.
Por ejemplo :
<Grid>
<!-- Combobox declared first -->
<ComboBox Name="comboBox1"
Margin="10"
SelectedIndex="0"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox>
<!-- Label declared later -->
<Label Name="label1"
Content="Label"
Margin="10" />
</Grid>
Aquí se crea label1
antes de label1
. Si comboBox1_SelectionChanged
intenta hacer referencia a `label1, aún no se habrá creado.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Cambiar el orden de las declaraciones en el XAML (es decir, listar label1
antes de comboBox1
, ignorando los problemas de la filosofía de diseño, al menos resolvería la NullReferenceException
aquí.
Reparto con as
var myThing = someObject as Thing;
Esto no lanza una excepción InvalidCastException, pero devuelve un null
cuando falla la conversión (y cuando someObject es nulo). Así que sé consciente de eso.
LINQ FirstOrDefault () y SingleOrDefault ()
Las versiones simples First()
y Single()
lanzan excepciones cuando no hay nada. Las versiones "OrDefault" devuelven nulo en ese caso. Así que sé consciente de eso.
para cada
foreach
lanza cuando intentas iterar la colección nula. Usualmente causado por resultados null
inesperados de métodos que devuelven colecciones.
List<int> list = null;
foreach(var v in list) { } // exception
Ejemplo más realista: seleccione los nodos del documento XML. Se lanzará si no se encuentran los nodos pero la depuración inicial muestra que todas las propiedades son válidas:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Formas de evitar
Verifique explícitamente si hay valores null
e ignore valores nulos.
Si espera que la referencia a veces sea nula, puede verificar que sea null
antes de acceder a los miembros de la instancia:
void PrintName(Person p) {
if (p != null) {
Console.WriteLine(p.Name);
}
}
Verifique explícitamente el null
y proporcione un valor predeterminado.
Los métodos de llamada que espera devolver una instancia pueden devolver un null
, por ejemplo, cuando no se puede encontrar el objeto que se está buscando. Puede elegir devolver un valor predeterminado cuando este sea el caso:
string GetCategory(Book b) {
if (b == null)
return "Unknown";
return b.Category;
}
Verifique explícitamente el null
de las llamadas a métodos y lance una excepción personalizada.
También puede lanzar una excepción personalizada, solo para capturarla en el código de llamada:
string GetCategory(string bookTitle) {
var book = library.FindBook(bookTitle); // This may return null
if (book == null)
throw new BookNotFoundException(bookTitle); // Your custom exception
return book.Category;
}
Utilice Debug.Assert
si un valor nunca debe ser null
, para detectar el problema antes de que se produzca la excepción.
Cuando sabe durante el desarrollo que un método tal vez pueda, pero nunca debe devolver un null
, puede usar Debug.Assert()
para interrumpirse lo antes posible cuando ocurra:
string GetTitle(int knownBookID) {
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn''t return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
Aunque esta comprobación no terminará en su versión de lanzamiento , causará que se vuelva a lanzar la NullReferenceException
cuando book == null
en el tiempo de ejecución en el modo de lanzamiento.
Use GetValueOrDefault()
para tipos de valores que admiten valores null
para proporcionar un valor predeterminado cuando son null
.
DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
Utilice el operador de unión nula: ??
[C #] o If()
[VB].
La abreviatura para proporcionar un valor predeterminado cuando se encuentra un valor null
:
IService CreateService(ILogger log, Int32? frobPowerLevel)
{
var serviceImpl = new MyService(log ?? NullLog.Instance);
// Note that the above "GetValueOrDefault()" can also be rewritten to use
// the coalesce operator:
serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}
Utilice el operador de condición nula: ?.
o ?[x]
para matrices (disponible en C # 6 y VB.NET 14):
Esto también a veces se denomina operador de navegación segura o Elvis (después de su forma). Si la expresión en el lado izquierdo del operador es nula, entonces el lado derecho no se evaluará, y en su lugar se devuelve nulo. Eso significa casos como este:
var title = person.Title.ToUpper();
Si la persona no tiene un título, esto generará una excepción porque está intentando llamar a ToUpper
en una propiedad con un valor nulo.
En C # 5 y más abajo, esto puede ser protegido con:
var title = person.Title == null ? null : person.Title.ToUpper();
Ahora la variable de título será nula en lugar de lanzar una excepción. C # 6 introduce una sintaxis más corta para esto:
var title = person.Title?.ToUpper();
Esto dará como resultado que la variable de título sea null
y la llamada a ToUpper
no se realice si person.Title
es null
.
Por supuesto, todavía tiene que verificar el title
para nulo o usar el operador de condición nula junto con el operador de unión nula ( ??
) para proporcionar un valor predeterminado:
// regular null check
int titleLength = 0;
if (title != null)
titleLength = title.Length; // If title is null, this would throw NullReferenceException
// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;
Del mismo modo, para matrices puede usar ?[i]
siguiente manera:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Esto hará lo siguiente: Si myIntArray es nulo, la expresión devuelve un valor nulo y puede verificarlo de manera segura. Si contiene una matriz, hará lo mismo que: elem = myIntArray[i];
y devuelve el elemento i th .
Técnicas especiales para depurar y reparar errores nulos en iteradores.
C # admite "bloques de iteradores" (llamados "generadores" en otros lenguajes populares). Las excepciones de anulación de nulos pueden ser particularmente difíciles de depurar en bloques de iteradores debido a la ejecución diferida:
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
...
FrobFactory factory = whatever;
IEnumerable<Frobs> frobs = GetFrobs();
...
foreach(Frob frob in frobs) { ... }
Si whatever
resultado es null
entonces MakeFrob
lanzará. Ahora, puedes pensar que lo correcto es esto:
// DON''T DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
if (f == null)
throw new ArgumentNullException("f", "factory must not be null");
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
¿Por qué está mal? ¡Porque el bloque iterador no se ejecuta realmente hasta el foreach
! La llamada a GetFrobs
simplemente devuelve un objeto que, cuando se itera , ejecutará el bloque del iterador.
Al escribir una comprobación nula como esta, se evita la anulación de la nula, pero se mueve la excepción de argumento nulo al punto de la iteración , no al punto de la llamada , y eso es muy confuso para la depuración .
La solución correcta es:
// DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
// No yields in a public method that throws!
if (f == null)
throw new ArgumentNullException("f", "factory must not be null");
return GetFrobsForReal(f, count);
}
private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
{
// Yields in a private method
Debug.Assert(f != null);
for (int i = 0; i < count; ++i)
yield return f.MakeFrob();
}
Es decir, cree un método auxiliar privado que tenga la lógica de bloque del iterador y un método de superficie pública que haga la comprobación nula y devuelva el iterador. Ahora, cuando se llama a GetFrobs
, la comprobación nula se realiza inmediatamente y, a continuación, GetFrobsForReal
ejecuta cuando se itera la secuencia.
Si examina la fuente de referencia de LINQ to Objects, verá que esta técnica se utiliza en todo momento. Escribir es un poco más complicado, pero facilita mucho la depuración de errores de nulidad. Optimice su código para la conveniencia de la persona que llama, no la conveniencia del autor .
Una nota sobre nereferencias en código inseguro
C # tiene un modo "inseguro" que es, como su nombre lo indica, extremadamente peligroso porque no se aplican los mecanismos de seguridad normales que proporcionan seguridad de memoria y seguridad de tipo. No debe escribir código no seguro a menos que tenga un conocimiento profundo y profundo de cómo funciona la memoria .
En el modo inseguro, debe tener en cuenta dos hechos importantes:
- la desreferenciación de un puntero nulo produce la misma excepción que la desreferenciación de una referencia nula
- la anulación de la referencia de un puntero no nulo no válido puede producir esa excepción en algunas circunstancias
Para entender por qué esto es así, es útil entender cómo .NET produce excepciones de anulación de nulos en primer lugar. (Estos detalles se aplican a .NET que se ejecuta en Windows; otros sistemas operativos usan mecanismos similares).
La memoria está virtualizada en Windows; Cada proceso obtiene un espacio de memoria virtual de muchas "páginas" de memoria que son rastreadas por el sistema operativo. Cada página de la memoria tiene indicadores establecidos que determinan cómo se puede usar: leer, escribir, ejecutar, etc. La página más baja está marcada como "produce un error si alguna vez se utiliza de alguna manera".
Tanto un puntero nulo como una referencia nula en C # se representan internamente como el número cero, por lo que cualquier intento de desreferenciarlo en su almacenamiento de memoria correspondiente hace que el sistema operativo produzca un error. El tiempo de ejecución de .NET luego detecta este error y lo convierte en la excepción de anulación nula.
Es por eso que la anulación de referencias tanto a un puntero nulo como a una referencia nula produce la misma excepción.
¿Qué pasa con el segundo punto? La eliminación de referencias a cualquier puntero no válido que se encuentre en la página más baja de la memoria virtual provoca el mismo error del sistema operativo y, por lo tanto, la misma excepción.
¿Por qué esto tiene sentido? Bueno, supongamos que tenemos una estructura que contiene dos ints y un puntero no administrado igual a nulo. Si intentamos eliminar la referencia al segundo int en la estructura, el CLR no intentará acceder al almacenamiento en la ubicación cero; Accederá al almacenamiento en la ubicación cuatro. Pero lógicamente esto es una anulación de nulas porque estamos llegando a esa dirección a través de la nula.
Si está trabajando con un código no seguro y obtiene una excepción de anulación de nulos, simplemente tenga en cuenta que el puntero ofensivo no necesita ser nulo. Puede ser cualquier ubicación en la página más baja, y se producirá esta excepción.
Tengo algo de código y cuando se ejecuta, lanza una NullReferenceException
, diciendo:
Referencia a objeto no establecida como instancia de un objeto.
¿Qué significa esto y qué puedo hacer para corregir este error?
Excepción de referencia nula - Visual Basic
La NullReference Exception
para Visual Basic no es diferente de la de C # . Después de todo, ambos reportan la misma excepción definida en el .NET Framework que ambos usan. Las causas únicas de Visual Basic son raras (quizás solo una).
Esta respuesta utilizará los términos, la sintaxis y el contexto de Visual Basic. Los ejemplos utilizados provienen de un gran número de preguntas anteriores de desbordamiento de pila. Esto es para maximizar la relevancia mediante el uso de los tipos de situaciones que se ven a menudo en las publicaciones. También se proporciona un poco más de explicación para aquellos que puedan necesitarla. Un ejemplo similar al suyo es muy probable que aparezca aquí.
Nota:
- Esto se basa en conceptos: no hay código para pegar en su proyecto. Está pensado para ayudarlo a comprender las causas de una
NullReferenceException
(NRE), cómo encontrarlo, cómo solucionarlo y cómo evitarlo. Una NRE puede ser causada de muchas maneras, por lo que es poco probable que este sea su único encuentro. - Los ejemplos (de publicaciones de desbordamiento de pila) no siempre muestran la mejor manera de hacer algo en primer lugar.
- Normalmente, se utiliza el remedio más simple.
Significado básico
El mensaje "Objeto no establecido en una instancia de Objeto" significa que está intentando usar un objeto que no se ha inicializado. Esto se reduce a uno de estos:
- Su código declaró una variable de objeto, pero no la inicializó (cree una instancia o ''la instancia '')
- Algo que su código supuso inicializaría un objeto, no lo hizo
- Posiblemente, otro código invalidó prematuramente un objeto todavía en uso
Encontrar la causa
Dado que el problema es una referencia de objeto que es Nothing
, la respuesta es examinarlos para averiguar cuál. Luego determina por qué no está inicializado. Mantenga el mouse sobre las diversas variables y Visual Studio (VS) mostrará sus valores: el culpable será Nothing
.
También debe eliminar cualquier bloque Try / Catch del código relevante, especialmente aquellos donde no hay nada en el bloque Catch. Esto provocará que su código se bloquee cuando intenta usar un objeto que es Nothing
. Esto es lo que desea, ya que identificará la ubicación exacta del problema y le permitirá identificar el objeto que lo causa.
Un MsgBox
en el Catch que muestra Error while...
será de poca ayuda. Este método también conduce a muy malas preguntas de desbordamiento de pila, porque no puede describir la excepción real, el objeto involucrado o incluso la línea de código donde ocurre.
También puede usar la Locals Window
( Depurar -> Windows -> Locales ) para examinar sus objetos.
Una vez que sepa cuál y dónde está el problema, generalmente es bastante fácil de arreglar y más rápido que publicar una nueva pregunta.
Ver también:
- Breakpoints
- MSDN: Cómo usar el bloque Try / Catch para atrapar excepciones
- MSDN: Mejores Prácticas para Excepciones
Ejemplos y remedios
Objetos de clase / Creación de una instancia
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount '' NRE
El problema es que Dim
no crea un objeto CashRegister; solo declara una variable llamada reg
de ese tipo. Declarar una variable de objeto y crear una instancia son dos cosas diferentes.
Remedio
El New
operador puede usarse a menudo para crear la instancia cuando la declara:
Dim reg As New CashRegister '' [New] creates instance, invokes the constructor
'' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Cuando solo es apropiado crear la instancia más tarde:
Private reg As CashRegister '' Declare
...
reg = New CashRegister() '' Create instance
Nota: No utilice Dim
nuevamente en un procedimiento, incluido el constructor ( Sub New
):
Private reg As CashRegister
''...
Public Sub New()
''...
Dim reg As New CashRegister
End Sub
Esto creará una variable local , reg
, que existe solo en ese contexto (sub). La variable reg
con el Scope
nivel de módulo que utilizará en cualquier otro lugar permanece en Nothing
.
Falta el
New
operador es la causa número 1 de lasNullReference Exceptions
deNullReference Exceptions
deNullReference Exceptions
observadas 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 llama aSub New
, el constructor, donde su objeto puede realizar cualquier otra inicialización.
Para ser claros, Dim
(o Private
) solo declara una variable y su Type
. El alcance de la variable, ya sea que exista para todo el módulo / clase o sea local para un procedimiento, se determina según dónde se declara. Private | Friend | Public
Private | Friend | Public
define el nivel de acceso, no el alcance .
Para más información, ver:
- Nuevo operador
- Ámbito en Visual Basic
- Niveles de acceso en Visual Basic
- Tipos de valor y tipos de referencia
Arrays
Las matrices también deben ser instanciadas:
Private arr as String()
Esta matriz solo ha sido declarada, no creada. Hay varias formas de inicializar una matriz:
Private arr as String() = New String(10){}
'' or
Private arr() As String = New String(10){}
'' For a local array (in a procedure) and using ''Option Infer'':
Dim arr = New String(10) {}
Nota: A partir de VS 2010, al inicializar una matriz local utilizando un literal y la Option Infer
, los elementos As <Type>
y New
son opcionales:
Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}
El tipo de datos y el tamaño de la matriz se deducen de los datos que se asignan. Las declaraciones de nivel de clase / módulo aún requieren As <Type>
con Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Ejemplo: matriz de objetos de clase
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 '' Exception
Next
Se ha creado la matriz, pero no los objetos Foo
en ella.
Remedio
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() '' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Usar una List(Of T)
hará que sea bastante difícil tener un elemento sin un objeto válido:
Dim FooList As New List(Of Foo) '' List created, but it is empty
Dim f As Foo '' Temporary variable for the loop
For i As Integer = 0 To 5
f = New Foo() '' Foo instance created
f.Bar = i * 10
FooList.Add(f) '' Foo object added to list
Next
Para más información, ver:
Listas y colecciones
Las colecciones .NET (de las cuales hay muchas variedades - Listas, Diccionario, etc.) también deben crearse o crear instancias.
Private myList As List(Of String)
..
myList.Add("ziggy") '' NullReference
Obtienes la misma excepción por el mismo motivo: myList
solo se declaró, pero no se creó ninguna instancia. El remedio es el mismo:
myList = New List(Of String)
'' Or create an instance when declared:
Private myList As New List(Of String)
Un descuido común es una clase que usa un Type
colección:
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
Cualquiera de los procedimientos resultará en un NRE, porque la lista de barList
solo se declara, no se barList
una instancia. La creación de una instancia de Foo
no creará también una instancia de la lista de barList
interna. Puede haber sido la intención de hacer esto en el constructor:
Public Sub New '' Constructor
'' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Como antes, esto es incorrecto:
Public Sub New()
'' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Para obtener más información, consulte Clase de List(Of T)
.
Objetos del proveedor de datos
Trabajar con bases de datos presenta muchas oportunidades para una NullReference porque puede haber muchos objetos ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
...) en uso al mismo tiempo. Nota: No importa qué proveedor de datos esté utilizando - MySQL, SQL Server, OleDB, etc. - los conceptos son los mismos.
Ejemplo 1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer
con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count '' Error
Como antes, se declaró el objeto ds
datos, pero nunca se creó una instancia. El DataAdapter
llenará un DataSet
existente, no creará uno. En este caso, dado que ds
es una variable local, el IDE le advierte que esto podría suceder:
Cuando se declara como una variable de módulo / nivel de clase, como parece ser el caso con con
, el compilador no puede saber si el objeto fue creado por un procedimiento ascendente. No ignore las advertencias.
Remedio
Dim ds As New DataSet
Ejemplo 2
ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")
txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)
Un error tipográfico es un problema aquí: Employees
vs Employee
. No se creó una NullReferenceException
datos llamada "Empleado", por lo que se obtiene un NullReferenceException
intenta acceder a ella. Otro problema potencial es asumir que habrá Items
que pueden no ser así cuando el SQL incluye una cláusula WHERE.
Remedio
Como esto usa una tabla, el uso de Tables(0)
evitará errores ortográficos. Examinar Rows.Count
también puede ayudar:
If ds.Tables(0).Rows.Count > 0 Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If
Fill
es una función que devuelve el número de Rows
afectadas que también se pueden probar:
If da.Fill(ds, "Employees") > 0 Then...
Ejemplo 3
Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)
If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then
El DataAdapter
proporcionará TableNames
como se muestra en el ejemplo anterior, pero no analiza los nombres de la tabla SQL o de la base de datos. Como resultado, ds.Tables("TICKET_RESERVATION")
referencia a una tabla que no existe.
El remedio es el mismo, referencia la tabla por índice:
If ds.Tables(0).Rows.Count > 0 Then
Véase también la clase DataTable .
Rutas de objeto / anidadas
If myFoo.Bar.Items IsNot Nothing Then
...
El código solo está probando Items
mientras que myFoo
y Bar
también pueden ser Nothing. El remedio es probar la cadena completa o la ruta de los objetos uno a la vez:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
es importante. Las pruebas posteriores no se realizarán una vez que se encuentre la primera condición False
. Esto permite que el código "explore" de forma segura el (los) objeto (s) "nivel" a la vez, evaluando myFoo.Bar
solo después de (y si) se determina que myFoo
es válido. Las cadenas o rutas de objetos pueden ser bastante largas al codificar objetos complejos:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
No es posible hacer referencia a nada ''corriente abajo'' de un objeto null
. Esto también se aplica a los controles:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Aquí, myWebBrowser
o Document
podría ser Nothing o el elemento formfld1
podría no existir.
Controles de interfaz de usuario
Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
& "FROM Invoice where invoice_no = ''" & _
Me.ComboBox5.SelectedItem.ToString.Trim & "'' And category = ''" & _
Me.ListBox1.SelectedItem.ToString.Trim & "'' And item_name = ''" & _
Me.ComboBox2.SelectedValue.ToString.Trim & "'' And expiry_date = ''" & _
Me.expiry.Text & "''", con)
Entre otras cosas, este código no anticipa que el usuario no haya seleccionado algo en uno o más controles de UI. ListBox1.SelectedItem
bien puede ser Nothing
, por lo que ListBox1.SelectedItem.ToString
dará lugar a 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...
Formas de Visual Basic
Public Class Form1
Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}
'' same thing in a different format:
Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}
'' Immediate NRE:
Private somevar As String = Me.Controls("TextBox1").Text
Esta es una forma bastante común de obtener una NRE. En C #, dependiendo de cómo esté codificado, el IDE informará que Controls
no existe en el contexto actual, o "no puede hacer referencia al miembro no estático". Por lo tanto, hasta cierto punto, esta es una situación solo de VB. También es complejo porque puede dar lugar a una falla en cascada.
Las matrices y colecciones no se pueden inicializar de esta manera. Este código de inicialización se ejecutará antes de que el constructor cree el Form
o el Controls
. Como resultado:
- Las listas y la colección simplemente estarán vacías
- El Array contendrá cinco elementos de Nada.
- La
somevar
asignación resultará en una NRE inmediata porque Nothing no tiene una.Text
propiedad
Hacer referencia a los elementos de la matriz más adelante resultará en una NRE. Si hace esto en Form_Load
, debido a un error extraño, el IDE puede no informar la excepción cuando sucede. La excepción aparecerá más adelante cuando su código intente utilizar la matriz. Esta "excepción silenciosa" se detalla en esta publicación . Para nuestros propósitos, la clave es que cuando ocurre algo catastrófico al crear un formulario ( Sub 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 su evento Sub New
o Form Load
evento se ejecutará después de la NRE, muchas otras cosas pueden dejarse sin inicializar.
Sub Form_Load(..._
''...
Dim name As String = NameBoxes(2).Text '' NRE
'' ...
'' More code (which will likely not be executed)
'' ...
End Sub
Tenga en cuenta que esto se aplica a todas y cada una de las referencias de control y componentes que hacen que estas sean ilegales donde se encuentran:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Remedio parcial
Es curioso que VB no proporciona una advertencia, pero el remedio es declarar los contenedores en el nivel de la forma, pero inicializar en controlador de eventos de carga de formulario cuando los controles no existen. Esto se puede hacer Sub New
mientras 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. Cualquier control que se encuentre en un control de contenedor (como a GroupBox
o Panel
) no se encontrará en Me.Controls
; estarán en la colección de Controles de ese Panel o GroupBox. Tampoco se devolverá un control cuando el nombre del control esté mal escrito ( "TeStBox2"
). En tales casos, Nothing
se almacenará nuevamente en esos elementos de la matriz y se generará una NRE cuando intente hacer referencia a ella.
Estos deberían ser fáciles de encontrar ahora que sabes lo que estás buscando:
"Button2" reside en un Panel
Remedio
En lugar de referencias indirectas por nombre utilizando la 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...})
Función que no devuelve nada
Private bars As New List(Of Bars) '' Declared and created
Public Function BarList() As List(Of Bars)
bars.Clear
If someCondition Then
For n As Integer = 0 to someValue
bars.Add(GetBar(n))
Next n
Else
Exit Function
End If
Return bars
End Function
Este es un caso en el que el IDE le advertirá que '' no todas las rutas devuelven un valor y NullReferenceException
puede resultar en un '' 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
se traducirá en un 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 regresar Nothing
. Si existe la posibilidad de que un objeto devuelto pueda ser Nothing
, pruebe antes de usarlo:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Mal implementado Try / Catch
Un Try / Catch mal implementado puede ocultar dónde está el problema y generar otros nuevos:
Dim dr As SqlDataReader
Try
Dim lnk As LinkButton = TryCast(sender, LinkButton)
Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username") = eid
sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username=''" & eid & "''"
If connection.State <> ConnectionState.Open Then
connection.Open()
End If
command = New SqlCommand(sqlQry, connection)
''More code fooing and barring
dr = command.ExecuteReader()
If dr.Read() Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))
...
End If
mpe.Show()
Catch
Finally
command.Dispose()
dr.Close() '' <-- NRE
connection.Close()
End Try
Este es un caso de un objeto que no se crea como se espera, pero también demuestra la utilidad del contador de un vacío Catch
.
Hay una coma adicional en el SQL (después de ''mailaddress'') que da como resultado una excepción en .ExecuteReader
. Después de Catch
que no haga nada, Finally
intente realizar una limpieza, pero como no puede hacer Close
un DataReader
objeto nulo , los NullReferenceException
resultados son nuevos .
Un Catch
bloque vacío es el patio del diablo. Este OP estaba desconcertado por la razón por la que obtuvo una NRE en el Finally
bloque. En otras situaciones, un vacío Catch
puede resultar en algo mucho más lejano hacia abajo y se puede hacer que pases el tiempo mirando las cosas equivocadas en el lugar equivocado para el problema. (La "excepción silenciosa" descrita anteriormente proporciona el mismo valor de entretenimiento).
Remedio
No utilice bloques de prueba / captura vacíos: deje que el código se bloquee para que pueda a) identificar la causa b) identificar la ubicación yc) aplicar un remedio adecuado. Los bloques Try / Catch no pretenden ocultar excepciones de la persona calificada de forma única para solucionarlos: el desarrollador.
DBNull no es lo mismo que Nothing
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
La IsDBNull
función se usa para probar si un valor es igual a System.DBNull
: De MSDN:
El valor System.DBNull indica que el Objeto representa datos faltantes o inexistentes. DBNull no es lo mismo que Nothing, lo que indica que una variable aún no se ha inicializado.
Remedio
If row.Cells(0) IsNot Nothing Then ...
Como antes, puedes probar para Nothing, luego para un valor específico:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Ejemplo 2
Dim getFoo = (From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
If Not IsDBNull(getFoo) Then
If IsDBNull(getFoo.user_id) Then
txtFirst.Text = getFoo.first_name
Else
...
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 una CheckBox
con chkName
no se puede encontrar (o existe en una GroupBox
), entonces chk
habrá nada y estar intentando hacer referencia a cualquier propiedad dará lugar a una excepción.
Remedio
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
El DataGridView
La DGV tiene algunas peculiaridades que se ven periódicamente:
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True '' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
Si lo dgvBooks
ha hecho AutoGenerateColumns = True
, creará las columnas, pero no las nombra, por lo que el código anterior falla cuando las hace referencia por su nombre.
Remedio
Nombra las columnas manualmente, o referencia por índice:
dgvBooks.Columns(0).Visible = True
Ejemplo 2 - Cuidado con el NewRow
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
Cuando su DataGridView
tiene AllowUserToAddRows
como True
(el valor predeterminado), el Cells
en la fila en blanco / nueva en la parte inferior contendrá Nothing
. La mayoría de los intentos de usar los contenidos (por ejemplo, ToString
) resultarán en una NRE.
Remedio
Use un For/Each
bucle y pruebe la IsNewRow
propiedad para determinar si es la ú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 utiliza un For n
bucle, modifique el recuento de filas o use Exit For
cuando IsNewRow
sea verdadero.
Mis.Ajustes (StringCollection)
Bajo ciertas circunstancias, intentar usar un elemento desde el My.Settings
cual se StringCollection
puede generar una NullReference la primera vez que lo use. La solución es la misma, pero no tan obvia. Considerar:
My.Settings.FooBars.Add("ziggy") '' foobars is a string collection
Dado que VB está administrando las configuraciones por usted, es razonable esperar que inicialice la colección. Lo hará, pero solo si previamente ha agregado una entrada inicial a la colección (en el editor de Configuración). Dado que la colección se inicializa (aparentemente) cuando se agrega un elemento, permanece 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 / cuando sea necesario:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Normalmente, la Settings
colección solo tendrá que inicializarse la primera vez que se ejecute la aplicación. Un remedio alternativo es agregar un valor inicial a su colección en Proyecto -> Configuración | FooBars , guarda el proyecto, luego elimina el valor falso.
Puntos clave
Probablemente te olvidaste del 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).
¿Qué puedes hacer al respecto?
Aquí hay muchas respuestas buenas que explican qué es una referencia nula y cómo depurarla. Pero hay muy poco sobre cómo prevenir el problema o, al menos, facilitar la captura.
Comprobar argumentos
Por ejemplo, los métodos pueden verificar los diferentes argumentos para ver si son nulos y lanzar ArgumentNullException
una excepción, obviamente creada para este propósito exacto.
El constructor de la 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.");
}
}
Utilizar herramientas
También hay varias bibliotecas que pueden ayudar. "Resharper", por ejemplo, puede proporcionarle advertencias mientras escribe el código, especialmente si usa su atributo: NotNullAttribute
Hay "Contratos de código de Microsoft" en los que se utiliza una sintaxis como la Contract.Requires(obj != null)
que le proporciona la verificación en tiempo de ejecución y compilación: Introducción de contratos de código .
También hay "PostSharp" que te permitirá usar atributos como este:
public void DoSometing([NotNull] obj)
Al hacer eso y hacer que PostSharp sea parte de su proceso de compilación obj
, se comprobará si está vacío en el tiempo de ejecución. Ver: PostSharp cheque nulo
Solución de código simple
O siempre puede codificar su propio enfoque utilizando un código antiguo. Por ejemplo, aquí hay una estructura que puede usar para capturar referencias nulas. Se modela siguiendo 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 de forma muy similar a la 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 lanzado hacia y desde, de T
modo que puede usarlo en cualquier lugar que lo necesite. Por ejemplo, puede pasar un Person
objeto a un método que toma un NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Como puede ver arriba, como con Nullable, accederá 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 siguiente valor de retorno:
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, el siguiente código le gustaría simplemente el código anterior:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combinar con extensión
Combine NotNull<T>
con un método de extensión y podrá cubrir incluso más situaciones. Aquí hay un ejemplo de cómo puede verse el método de extensión:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
Y aquí hay un ejemplo de cómo podría usarse:
var person = GetPerson().NotNull();
GitHub
Para su referencia, puse el código arriba disponible en GitHub, lo puede encontrar en:
https://github.com/luisperezphd/NotNull
Característica del lenguaje relacionado
C # 6.0 introdujo el "operador condicional nulo" que ayuda con esto un poco. Con esta característica, puede hacer referencia a objetos anidados y, si alguno de ellos es el resultado de null
la expresión completa null
.
Esto reduce el número de comprobaciones nulas que tiene que hacer en algunos casos. La sintaxis es poner un signo de interrogación antes de cada punto. Toma el siguiente código por ejemplo:
var address = country?.State?.County?.City;
Imagina 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 te da menos información. No deja en claro cuál de los 4 es nulo.
¿Incorporado como Nullable?
C # tiene una buena forma abreviada de Nullable<T>
, puedes hacer algo anulable al poner un signo de interrogación después del tipo comoint?
.
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)
.
TL; DR: Trate de usar en Html.Partial
lugar deRenderpage
Estaba recibiendo Object reference not set to an instance of an object
cuando intenté renderizar una Vista dentro de una Vista enviándole un Modelo, como este:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
La depuración mostró que el modelo era nulo dentro de MyOtherView. Hasta que lo cambié a:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Y funcionó.
Además, la razón por la que no tenía Html.Partial
que empezar era porque Visual Studio a veces arroja líneas onduladas con aspecto de error Html.Partial
si está dentro de un foreach
bucle construido de manera diferente , aunque no sea realmente un error:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group ''partial'' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
Pero pude ejecutar la aplicación sin problemas con este "error". Pude deshacerme del error cambiando la estructura del foreach
bucle para tener este aspecto:
@foreach(var M in MyEntities){
...
}
Aunque tengo la sensación de que fue porque Visual Studio no leía correctamente los símbolos y los paréntesis.
Agregar un caso cuando el nombre de clase para la entidad utilizada en el marco de la entidad es el mismo que el nombre de clase para un archivo de código subyacente de formulario web.
Supongamos que tiene un formulario web Contact.aspx cuya clase de código es Contact y tiene un nombre de entidad Contact.
Luego, el siguiente código lanzará una NullReferenceException cuando llame a context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Por el bien de la clase DataContext completa
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
y clase de entidad de contacto. A veces, las clases de entidad son clases parciales, por lo que también puede extenderlas a otros archivos.
public partial class Contact
{
public string Name {get; set;}
}
El error se produce cuando tanto la entidad como la clase de código están en el mismo espacio de nombres. Para solucionar esto, cambie el nombre de la clase de entidad o la clase de código de enlace para Contact.aspx.
Razón todavía no estoy seguro de la razón. Pero cada vez que cualquiera de la clase de entidad extenderá System.Web.UI.Page, se producirá este error.
Para discusión, eche un vistazo a NullReferenceException en DbContext.saveChanges ()
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:
Depure y deje que el depurador se rompa ... Lo llevará directamente a la variable que está rota ... Ahora su tarea es simplemente arreglar esto ... Usar 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, todo lo que necesita hacer es realizar una comprobación nula y manejarlo:
if (i == null) { // Handle this }
La más difícil ... si el GC recogió el objeto ... Esto generalmente ocurre si está tratando de encontrar un objeto utilizando cadenas ... Es decir, si lo encuentra por el nombre del objeto, puede 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 hacer verificaciones nulas cuando sea necesario durante el proceso de desarrollo. Esto te ahorrara mucho tiempo.
Al buscar por nombre me refiero a que algún marco te permite usar FIndObjects usando cadenas y el código podría tener este aspecto: FindObject ("ObjectName");
Curiosamente, ninguna de las respuestas en esta página menciona los dos casos de borde, espero que a nadie le importe si los agrego:
Caso de Edge # 1: acceso concurrente a un Diccionario
Los diccionarios genéricos en .NET no son seguros para subprocesos y, a veces, pueden lanzar uno NullReference
o incluso (más frecuente) KeyNotFoundException
cuando intenta acceder a una clave desde dos subprocesos simultáneos. La excepción es bastante engañosa en este caso.
Caso de Edge # 2: código inseguro
Si a NullReferenceException
es lanzado por unsafe
código, puede mirar sus variables de puntero y verificarlas IntPtr.Zero
o algo así. Que es lo mismo ("excepción de puntero nulo"), pero en el código no seguro, las variables a menudo se convierten a tipos de valor / arrays, etc. excepción.
(Otra razón para no usar código inseguro a menos que lo necesite, por cierto)
La línea de error "Referencia de objeto no establecida en una instancia de un objeto" indica que no ha asignado el objeto de instancia a una referencia de objeto y aún está accediendo a propiedades / métodos de ese objeto.
por ejemplo: digamos que tiene una clase llamada myClass y contiene una propiedad prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Ahora estás accediendo a esta prop1 en alguna otra clase como a continuación:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
la línea anterior arroja un error porque la referencia de la clase myClass se declara pero no se crea una instancia o una instancia del objeto no se asigna a la referencia de esa clase.
Para solucionar esto, debe crear una instancia (asignar el objeto a la referencia de esa clase).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
La referencia NullReferenceException o Object no establecida en una instancia de un objeto se produce cuando no se crea una instancia de un objeto de la clase que está intentando usar. Por ejemplo:
Supongamos que tienes una clase llamada Estudiante.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Ahora, considere otra clase en la que está intentando recuperar el nombre completo del estudiante.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Como se ve en el código anterior, la declaración Student s - solo declara la variable de tipo Student, tenga en cuenta que la clase de Student no está instanciada en este punto. Por lo tanto, cuando se ejecute la instrucción s.GetFullName () , lanzará la NullReferenceException.
Puede arreglar NullReferenceException de una manera limpia usando Operadores con Condición Nula en c # 6 y escribir menos código para manejar las verificaciones nulas.
Se utiliza para probar el valor nulo antes de realizar una operación de acceso de miembro (?.) O de índice (? [).
Ejemplo
var name = p?.Spouse?.FirstName;
es equivalente a:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
El resultado es que el nombre será nulo cuando p sea nulo o cuando p.Spouse sea nulo.
De lo contrario, al nombre de la variable se le asignará el valor de p.Spouse.FirstName.
Para más detalles: Operadores condicionales nulos
Si consideramos escenarios comunes donde se puede lanzar esta excepción, acceder a las propiedades con el objeto en la parte superior.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
aquí, si la dirección es nula, obtendrá NullReferenceException.
Por lo tanto, como práctica, siempre debemos utilizar la comprobación nula, antes de acceder a las propiedades en dichos objetos (especialmente en genéricos)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Si recibe este mensaje durante el guardado o la compilación, solo 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 aún estaba abierto.
Significa que su código utilizó una variable de referencia de objeto que se estableció en nulo (es decir, no hizo referencia a una instancia de objeto real).
Para evitar el error, los objetos que podrían ser nulos se deben probar con un valor nulo antes de ser utilizados.
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
Simon Mourier dio este ejemplo :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
donde una conversión de unboxing (conversión) de object
(o de una de las clases System.ValueType
o System.Enum
, o de un tipo de interfaz) a un tipo de valor (distinto de Nullable<>
) en sí mismo da el NullReferenceException
.
En la otra dirección, una conversión de boxeo de a Nullable<>
que tiene HasValue
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 sucede de otra manera. Por ejemplo, con este método de extensión no genérico:
public static void MyExtension(this object x)
{
x.ToString();
}
El siguiente código será problemático:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Estos casos surgen debido a las reglas especiales que el tiempo de ejecución utiliza cuando se encajonan Nullable<>
instancias.
Tenga en cuenta que, independientemente del escenario, la causa es siempre la misma en .NET:
Está intentando usar una variable de referencia cuyo valor es
Nothing
/null
. Cuando el valor 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, ni estableció la variable en
Nothing
/null
manualmente, o llamó a una función que estableció la variable enNothing
/null
para usted.
Un ejemplo de esta excepción que se lanza es: cuando intenta verificar algo, es nulo.
Por ejemplo:
string testString = null; //Because it doesn''t have a value (i.e. it''s null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
El tiempo de ejecución de .NET lanzará una NullReferenceException cuando intentes realizar una acción en algo que no haya sido instanciado, es decir, el código anterior.
En comparación con una ArgumentNullException que normalmente se lanza como una medida defensiva si un método espera que lo que se le pasa no sea nulo.
Más información está en C # NullReferenceException y Null Parameter .
A NullReferenceException
se genera cuando intentamos acceder a las Propiedades de un objeto nulo o cuando un valor de cadena se vacía y estamos tratando de acceder a los métodos de cadena.
Por ejemplo:
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
Está utilizando el objeto que contiene la referencia de valor nulo. Así que está dando una excepción nula. En el ejemplo, el valor de la cadena es nulo y al verificar su longitud, se produjo la excepción.
Ejemplo:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
El error de excepción es:
Excepción no controlada:
System.NullReferenceException: referencia de objeto no establecida en una instancia de un objeto. en Program.Main ()
Literalmente, la forma más fácil de arreglar una NullReferenceExeption tiene dos formas. Si tienes un GameObject, por ejemplo, con un script adjunto y una variable llamada rb (rigidbody), esta variable comenzará nula cuando comiences tu juego.
Es por eso que obtiene una NullReferenceExeption porque la computadora no tiene datos almacenados en esa variable.
Usaré una variable RigidBody como ejemplo.
Podemos agregar datos realmente fácilmente de varias maneras:
- Añadir un cuerpo rígido a su objeto con addComponent> Física> cuerpo rígido
y luego entrar en la secuencia de comandos y escribarb = GetComponent<Rigidbody>();
esta línea de código que funciona mejor bajo susStart()
oAwake()
funciones. - Puede agregar un componente programáticamente y asignar la variable al mismo tiempo con una línea de código:
rb = AddComponent<RigidBody>();
Notas adicionales: Si desea que la unidad agregue un componente a su objeto y se haya olvidado de agregar uno, puede escribir [RequireComponent(typeof(RigidBody))]
sobre su declaración de clase (el espacio debajo de todos sus usos).
Disfruta y diviértete haciendo juegos!
Los tipos de referencia se establecen como nulos para indicar que no hacen referencia a ningún objeto. Por lo tanto, si intenta acceder al objeto al que se hace referencia y no hay uno, obtendrá una NullReferenceException .
Por ejemplo:
SqlConnection connection = null;
connection.Open();
Cuando ejecute este código, obtendrá:
System.NullReferenceException: Object reference not set to an instance of an object.
Puedes evitar este error codificando así:
if (connection != null){
connection.Open();
}
Nota: Para evitar este error, siempre debe inicializar sus objetos antes de intentar hacer algo con ellos.
Otro caso donde NullReferenceExceptions
puede ocurrir 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 / convertir a a Book
. Cuando este reparto falla, as
vuelve null
. Usar mybook
después de esto causa a NullReferenceException
.
En general, debe utilizar un molde o as
, de la siguiente manera:
Si está esperando que la conversión de tipo siempre tenga éxito (es decir, sabe lo que el objeto debería estar adelantado), debe usar una conversión:
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) {
// ...
}
Otro caso general en el que uno podría recibir esta excepción involucra clases de burla durante la prueba de unidad. Independientemente de la estructura de simulacros que se esté utilizando, debe asegurarse de que todos los niveles apropiados de la jerarquía de clases estén correctamente burlados. En particular, todas las propiedades a las HttpContext
que hace referencia el código bajo prueba deben ser simuladas.
Consulte " NullReferenceException lanzada al probar el atributo de autorización personalizado " para ver un ejemplo un tanto detallado.
Otro escenario es cuando se convierte un objeto nulo en un tipo de valor . Por ejemplo, el siguiente código:
object o = null;
DateTime d = (DateTime)o;
Va a tirar NullReferenceException
sobre el yeso. Parece bastante obvio en el ejemplo anterior, pero esto puede suceder en escenarios más complejos e "de enlace tardío" en los que el objeto nulo ha sido devuelto desde algún código que no posee, y la conversión se genera, por ejemplo, por algún sistema automático.
Un ejemplo de esto es este simple fragmento de enlace de ASP.NET con el control de calendario:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Aquí, SelectedDate
de hecho , es una propiedad de DateTime
tipo de tipo de Calendar
control web, y el enlace podría devolver perfectamente algo nulo. El Generador de ASP.NET implícito creará un fragmento de código que será equivalente al código de conversión anterior. Y esto aumentará un NullReferenceException
que es bastante difícil de detectar, porque se encuentra en el código generado por ASP.NET que compila bien ...
Para usar los métodos y el miembro de un objeto, primero tiene que crear ese objeto. Si no lo creó (la variable que debe contener el objeto no está inicializada), pero si intenta usar sus métodos o variables, obtendrá ese error.
En algún momento puedes olvidarte de hacer la inicialización.
Editado: nuevo no puede devolver nulo, pero la excepción de fuego cuando falla. Hace mucho tiempo fue el caso en algunos idiomas, pero ya no. Gracias a @John Saunders por señalarlo.
Si bien lo que provoca un NullReferenceExceptions y enfoques para evitar / corregir tal excepción se han abordado en otras respuestas, lo que muchos programadores no han aprendido todavía cómo es independiente depurar las excepciones durante el desarrollo.
En Visual Studio, esto suele ser fácil gracias al depurador de Visual Studio .
Primero, asegúrese de que se detectará el error correcto; consulte ¿Cómo permito que se rompa en ''System.NullReferenceException'' en VS2010? Nota 1
Luego comience con la depuración (F5) o adjunte [el depurador VS] al proceso en ejecución . En ocasiones puede ser útil usarlo Debugger.Break
, lo que le pedirá que inicie el depurador.
Ahora, cuando se lanza (o no se maneja) la NullReferenceException, el depurador se detendrá (¿recuerda la regla establecida arriba?) En la línea en la que ocurrió la excepción. A veces el error será fácil de detectar.
Por ejemplo, en la siguiente línea, el único código que puede causar la excepción es si se myString
evalúa como nulo. Esto se puede verificar mirando la Ventana de Vigilancia o ejecutando expresiones en la Ventana Inmediata .
var x = myString.Trim();
En casos más avanzados, como los siguientes, deberá usar una de las técnicas anteriores (Ver o Windows Inmediato) para inspeccionar las expresiones para determinar si str1
fue nulo o si str2
fue nulo.
var x = str1.Trim() + str2.Trim();
Una vez que se ha localizado la excepción de lanzamiento, es generalmente trivial razonar hacia atrás para descubrir dónde se introdujo [incorrectamente] el valor nulo -
Tómese el tiempo necesario para comprender la causa de la excepción. Inspeccionar para expresiones nulas. Inspeccione las expresiones anteriores que podrían haber resultado en tales expresiones nulas. Agregue breakpoints y siga el programa según corresponda. Usa el depurador.
1 Si Break on Throws es demasiado agresivo y el depurador se detiene en una NPE en la biblioteca .NET o de terceros, se puede usar Break on Unmanled para limitar las excepciones detectadas. Además, VS2012 presenta Just My Code, que también recomiendo habilitar.
Si está depurando con Just My Code habilitado, el comportamiento es ligeramente diferente. Con Just My Code habilitado, el depurador ignora las excepciones de Common Language Runtime (CLR) de primera oportunidad que se lanzan fuera de My Code y no pasan por My Code
Si no ha inicializado un tipo de referencia y desea establecer o leer una de sus propiedades, lanzará una NullReferenceException .
Ejemplo:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Simplemente puede evitar esto comprobando si la variable no es nula:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Para comprender completamente por qué se emite una NullReferenceException, es importante conocer la diferencia entre los tipos de valor y los tipos de referencia .
Por lo tanto, si está tratando con tipos de valor , NullReferenceExceptions no puede ocurrir. ¡Aunque necesita estar alerta cuando se trata de tipos de referencia !
Solo los tipos de referencia, como sugiere el nombre, pueden contener referencias o apuntar literalmente a nada (o ''nulo''). Mientras que los tipos de valor siempre contienen un valor.
Tipos de referencia (estos deben ser marcados):
- dinámica
- objeto
- cuerda
Tipos de valor (simplemente puede ignorar estos):
- Tipos numericos
- Tipos integrales
- Tipos de punto flotante
- decimal
- bool
- Estructuras definidas por el usuario
Significa que está intentando manipular algo que tiene referencia pero aún no se ha inicializado.
Lo primero que debe hacer aquí es verificar cada instancia creada.
Utilice puntos de interrupción, relojes, inspeccione sus valores de varibales.
Siga el seguimiento de la pila y busque la fila y columna exactas que están creando problemas
Significa que la variable en cuestión no apunta a nada. Podría generar esto así:
SqlConnection connection = null;
connection.Open();
Eso arrojará el error porque, si bien he declarado la variable " connection
", no apunta a nada. Cuando trato de llamar al miembro " Open
", no hay ninguna referencia para que se resuelva, y arrojará el error.
Para evitar este error:
- Siempre inicialice sus objetos antes de intentar hacer algo con ellos.
- Si no está seguro de si el objeto es nulo, verifíquelo con
object == null
.
La herramienta Resharper de JetBrains identificará cada lugar en su código que tenga la posibilidad de un error de referencia nula, lo que le permite poner una comprobación nula. Este error es la fuente número uno de errores, IMHO.
Sobre el tema de "qué debo hacer al respecto" , puede haber muchas respuestas.
Una forma más "formal" de prevenir tales condiciones de error durante el desarrollo es aplicar el diseño por contrato en su código. Esto significa que necesita configurar invariantes de clase , y / o incluso condiciones previas de función / método y postcondiciones en su sistema, mientras se desarrolla.
En resumen, los invariantes de clase aseguran que habrá algunas restricciones en su clase que no serán violadas en el uso normal (y, por lo tanto, la clase no se pondrá en un estado inconsistente). Las condiciones previas significan que los datos dados como entrada a una función / método deben seguir algunas restricciones establecidas y nunca violarlas, y las condiciones posteriores significan que la salida de una función / método debe seguir las restricciones establecidas nuevamente sin violarlas nunca. Las condiciones del contrato nunca deben violarse durante la ejecución de un programa sin errores, por lo tanto, el diseño por contrato se verifica en la práctica en el modo de depuración, mientras se deshabilita en las versiones , para maximizar el rendimiento del sistema desarrollado.
De esta manera, puede evitar los NullReferenceException
casos que son el resultado de la violación del conjunto de restricciones. 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 llevará a NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Pero si establece "la propiedad X nunca debe tener un valor nulo" como condición previa del método, entonces puede evitar el escenario descrito anteriormente:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Por esta causa, existe un proyecto de Contratos de Código para aplicaciones .NET.
Alternativamente, el diseño por contrato puede ser aplicado usando assertions .
ACTUALIZACIÓN: vale la pena mencionar que el término fue acuñado por Bertrand Meyer en relación con su diseño del lenguaje de programación Eiffel .
Tengo una perspectiva diferente para responder a 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, se puede usar el Dependency Injection Container para inicializar los servicios y evitar la NullReferenceException . Así que eso significa que no tiene que preocuparse por verificar el valor nulo y simplemente llamar a los servicios desde el controlador como si siempre estuvieran disponibles (e inicializados) como singleton o prototipo.
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don''t need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}