J'ai du code et quand il s'exécute, il lance un NullReferenceException
, disant:
La référence d'objet n'est pas définie à une instance d'un objet.
Qu'est-ce que cela signifie et que puis-je faire pour corriger cette erreur?
J'ai du code et quand il s'exécute, il lance un NullReferenceException
, disant:
La référence d'objet n'est pas définie à une instance d'un objet.
Qu'est-ce que cela signifie et que puis-je faire pour corriger cette erreur?
Réponses:
Vous essayez d'utiliser quelque chose qui est null
(ou Nothing
dans VB.NET). Cela signifie que vous le définissez null
ou que vous ne le définissez jamais du tout.
Comme toute autre chose, se null
fait passer. S'il se trouve null
dans la méthode "A", il se peut que la méthode "B" soit passée null
à la méthode "A".
null
peut avoir différentes significations:
NullReferenceException
.null
intentionnellement pour indiquer qu'aucune valeur significative n'est disponible. Notez que C # a le concept de types de données nullables pour les variables (comme les tables de base de données peuvent avoir des champs nullables) - vous pouvez leur affecter null
pour indiquer qu'il n'y a pas de valeur stockée dedans, par exemple int? a = null;
lorsque le point d'interrogation indique qu'il est autorisé à stocker null dans variable a
. Vous pouvez vérifier cela avec if (a.HasValue) {...}
ou avec if (a==null) {...}
. Les variables nulles, comme a
cet exemple, permettent d'accéder à la valeur via a.Value
explicitement, ou tout simplement via via a
. a.Value
lance un InvalidOperationException
au lieu d'un NullReferenceException
if a
estnull
- vous devez faire la vérification au préalable, c'est-à-dire que si vous avez une autre variable on-nullable int b;
alors vous devez faire des affectations comme if (a.HasValue) { b = a.Value; }
ou plus courtes if (a != null) { b = a; }
.Le reste de cet article va plus en détail et montre les erreurs que de nombreux programmeurs font souvent et qui peuvent conduire à un NullReferenceException
.
Le runtime
jetant un NullReferenceException
toujours signifie la même chose: vous essayez d'utiliser une référence, et la référence n'est pas initialisé (ou il a été une fois initialisé, mais il est plus initialisé).
Cela signifie que la référence est null
et que vous ne pouvez pas accéder aux membres (tels que les méthodes) via une null
référence. Le cas le plus simple:
string foo = null;
foo.ToUpper();
Cela lancera un NullReferenceException
à la deuxième ligne car vous ne pouvez pas appeler la méthode d'instance ToUpper()
sur une string
référence pointant vers null
.
Comment trouvez-vous la source d'un NullReferenceException
? En plus de regarder l'exception elle-même, qui sera levée exactement à l'endroit où elle se produit, les règles générales de débogage dans Visual Studio s'appliquent: placez des points d'arrêt stratégiques et inspectez vos variables , soit en passant la souris sur leurs noms, en ouvrant un ( Rapide) Regardez la fenêtre ou utilisez les divers panneaux de débogage comme les sections locales et les automobiles.
Si vous souhaitez savoir où la référence est ou n'est pas définie, cliquez avec le bouton droit sur son nom et sélectionnez "Rechercher toutes les références". Vous pouvez ensuite placer un point d'arrêt à chaque emplacement trouvé et exécuter votre programme avec le débogueur attaché. Chaque fois que le débogueur s'arrête sur un tel point d'arrêt, vous devez déterminer si vous vous attendez à ce que la référence soit non nulle, inspecter la variable et vérifier qu'elle pointe vers une instance lorsque vous vous y attendez.
En suivant le flux du programme de cette façon, vous pouvez trouver l'emplacement où l'instance ne doit pas être nulle et pourquoi elle n'est pas correctement définie.
Quelques scénarios courants où l'exception peut être levée:
ref1.ref2.ref3.member
Si ref1 ou ref2 ou ref3 est nul, vous obtiendrez a NullReferenceException
. Si vous souhaitez résoudre le problème, recherchez celui qui est nul en réécrivant l'expression dans son équivalent le plus simple:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Plus précisément, dans HttpContext.Current.User.Identity.Name
, le HttpContext.Current
pourrait être nul, ou la User
propriété pourrait être nulle, ou la Identity
propriété pourrait être nulle.
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 vous souhaitez éviter la référence null enfant (Personne), vous pouvez l'initialiser dans le constructeur de l'objet parent (Livre).
La même chose s'applique aux initialiseurs d'objets imbriqués:
Book b1 = new Book
{
Author = { Age = 45 }
};
Cela se traduit par
Book b1 = new Book();
b1.Author.Age = 45;
Pendant que le new
mot-clé est utilisé, il crée seulement une nouvelle instance de Book
, mais pas une nouvelle instance de Person
, donc Author
la propriété est toujours null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
La collection imbriquée Initializers
se comporte de la même manière:
Person p1 = new Person
{
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Cela se traduit par
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
La new Person
seule crée une instance de Person
, mais la Books
collection est toujours null
. La Initializer
syntaxe de collection ne crée pas de collection pour p1.Books
, elle se traduit uniquement par les p1.Books.Add(...)
instructions.
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.
classe publique Form1 {client Client privé;
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);
}
}
Cela peut être résolu en suivant la convention pour préfixer les champs avec un trait de soulignement:
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 l'exception se produit lors du référencement d'une propriété de @Model
dans un ASP.NET MVC View
, vous devez comprendre que le Model
get est défini dans votre méthode d'action, lorsque vous return
une vue. Lorsque vous renvoyez un modèle vide (ou une propriété de modèle) à partir de votre contrôleur, l'exception se produit lorsque les vues y accèdent:
// 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
les contrôles sont créés lors de l'appel à InitializeComponent
dans l'ordre dans lequel ils apparaissent dans l'arborescence visuelle. Un NullReferenceException
sera soulevé dans le cas de contrôles créés au début avec des gestionnaires d'événements, etc., qui se déclenchent pendant InitializeComponent
lesquels référencent les contrôles créés tardivement.
Par exemple :
<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>
Ici comboBox1
est créé avant label1
. Si comboBox1_SelectionChanged
vous essayez de référencer `label1, il n'aura pas encore été créé.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Changer l'ordre des déclarations dans le XAML
(c.-à-d., Énumérer label1
avant comboBox1
, ignorer les problèmes de philosophie de conception, résoudrait au moins l' NullReferenceException
ici.
as
var myThing = someObject as Thing;
Cela ne lance pas un InvalidCastException
mais renvoie un null
lorsque le transtypage échoue (et quand someObject
est lui-même nul). Soyez donc conscient de cela.
FirstOrDefault()
etSingleOrDefault()
Les versions simples First()
et Single()
lèvent des exceptions quand il n'y a rien. Les versions "OrDefault" renvoient null dans ce cas. Soyez donc conscient de cela.
foreach
jette lorsque vous essayez d'itérer la collection null. Habituellement provoqué par un null
résultat inattendu des méthodes qui retournent des collections.
List<int> list = null;
foreach(var v in list) { } // exception
Exemple plus réaliste - sélectionnez des nœuds dans un document XML. Jettera si les nœuds ne sont pas trouvés mais le débogage initial montre que toutes les propriétés valides:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
et ignorez explicitement les valeurs nulles.Si vous vous attendez à ce que la référence soit parfois nulle, vous pouvez vérifier qu'elle est null
avant d'accéder aux membres de l'instance:
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
et fournissez explicitement une valeur par défaut.Les méthodes que vous prévoyez de renvoyer peuvent renvoyer une instance null
, par exemple lorsque l'objet recherché est introuvable. Vous pouvez choisir de renvoyer une valeur par défaut lorsque c'est le cas:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
appels de méthode et lancez une exception personnalisée.Vous pouvez également lever une exception personnalisée, uniquement pour l'attraper dans le code appelant:
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 une valeur ne doit jamais l'être null
, pour détecter le problème avant que l'exception ne se produise.Lorsque vous savez pendant le développement qu'une méthode peut peut-être, mais ne devrait jamais revenir null
, vous pouvez utiliser Debug.Assert()
pour interrompre dès que possible quand elle se produit:
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.
}
Bien que cette vérification ne se termine pas dans votre version , ce qui la fait lancer à NullReferenceException
nouveau lors book == null
de l'exécution en mode de publication.
GetValueOrDefault()
pour les nullable
types de valeur pour fournir une valeur par défaut lorsqu'ils le sont 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 #] ou If()
[VB].Le raccourci pour fournir une valeur par défaut quand un null
est rencontré:
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;
}
?.
ou ?[x]
pour les tableaux (disponibles en C # 6 et VB.NET 14):On l'appelle aussi parfois l'opérateur de navigation sécurisée ou Elvis (d'après sa forme). Si l'expression sur le côté gauche de l'opérateur est nulle, le côté droit ne sera pas évalué et null sera renvoyé à la place. Cela signifie des cas comme celui-ci:
var title = person.Title.ToUpper();
Si la personne n'a pas de titre, cela lèvera une exception car elle essaie d'appeler ToUpper
une propriété avec une valeur nulle.
Dans C# 5
et en dessous, cela peut être gardé avec:
var title = person.Title == null ? null : person.Title.ToUpper();
Maintenant, la variable de titre sera nulle au lieu de lever une exception. C # 6 introduit une syntaxe plus courte pour cela:
var title = person.Title?.ToUpper();
Cela se traduira par la variable de titre étant null
, et l'appel à ToUpper
n'est pas effectué si person.Title
est null
.
Bien sûr, vous devez toujours vérifier title
null ou utiliser l'opérateur de condition null avec l'opérateur de coalescence null ( ??
) pour fournir une valeur par défaut:
// 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;
De même, pour les tableaux, vous pouvez utiliser ?[i]
comme suit:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Cela fera ce qui suit: Si myIntArray
est null, l'expression renvoie null et vous pouvez le vérifier en toute sécurité. S'il contient un tableau, il fera la même chose que:
elem = myIntArray[i];
et renvoie l' i<sup>th</sup>
élément.
Introduits dans C# 8
ce contexte, les types de contexte nullable et de référence nullable effectuent une analyse statique sur les variables et fournissent un avertissement du compilateur si une valeur peut être potentiellement nulle ou avoir été définie sur null. Les types de référence nullable permettent aux types d'être explicitement autorisés à être null.
Le contexte d'annotation nullable et le contexte d'avertissement nullable peuvent être définis pour un projet à l'aide de l' Nullable
élément dans votre csproj
fichier. Cet élément configure la façon dont le compilateur interprète la nullité des types et quels avertissements sont générés. Les paramètres valides sont:
Un type de référence nullable est noté en utilisant la même syntaxe que les types de valeur nullable: a ?
est ajouté au type de la variable.
C#
prend en charge les "blocs d'itérateur" (appelés "générateurs" dans d'autres langues populaires). Les exceptions de déréférencement nul peuvent être particulièrement difficiles à déboguer dans les blocs d'itérateur en raison de l'exécution différée:
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 les whatever
résultats en null
puis MakeFrob
jettera. Maintenant, vous pourriez penser que la bonne chose à faire est la suivante:
// 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();
}
Pourquoi est-ce mal? Parce que le bloc itérateur ne s'exécute pas tant que le foreach
! L'appel à GetFrobs
renvoie simplement un objet qui, une fois itéré , exécutera le bloc itérateur.
En écrivant une vérification nulle comme celle-ci, vous empêchez la déréférence nulle, mais vous déplacez l'exception d'argument nul au point de l' itération , pas au point de l' appel , ce qui est très déroutant pour le débogage .
La solution correcte est:
// 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();
}
Autrement dit, créez une méthode d'assistance privée qui a la logique de blocage de l'itérateur et une méthode de surface publique qui effectue la vérification nulle et renvoie l'itérateur. Maintenant, quand GetFrobs
est appelé, la vérification nulle se produit immédiatement, puis GetFrobsForReal
s'exécute lorsque la séquence est itérée.
Si vous examinez la source de référence pour LINQ
to Objects, vous verrez que cette technique est utilisée partout. Il est légèrement plus maladroit à écrire, mais il facilite beaucoup le débogage des erreurs de nullité. Optimisez votre code pour la commodité de l'appelant et non pour la commodité de l'auteur .
C#
a un mode "dangereux" qui est, comme son nom l'indique, extrêmement dangereux car les mécanismes de sécurité normaux qui assurent la sécurité de la mémoire et la sécurité du type ne sont pas appliqués. Vous ne devez pas écrire de code dangereux à moins d'avoir une compréhension approfondie et approfondie du fonctionnement de la mémoire .
En mode non sécurisé, vous devez être conscient de deux faits importants:
Pour comprendre pourquoi, il est utile de comprendre comment .NET produit en premier lieu des exceptions de déréférencement nul. (Ces détails s'appliquent à .NET exécuté sur Windows; d'autres systèmes d'exploitation utilisent des mécanismes similaires.)
La mémoire est virtualisée dans Windows
; chaque processus obtient un espace de mémoire virtuelle de nombreuses "pages" de mémoire qui sont suivies par le système d'exploitation. Chaque page de mémoire comporte des indicateurs qui déterminent comment elle peut être utilisée: lecture, écriture, exécution, etc. La page la plus basse est marquée comme "produire une erreur si jamais utilisée de quelque façon que ce soit".
Un pointeur nul et une référence nulle dans C#
sont représentés en interne sous la forme du nombre zéro, et donc toute tentative de déréférencement dans son stockage mémoire correspondant entraîne une erreur du système d'exploitation. Le runtime .NET détecte ensuite cette erreur et la transforme en exception de déréférence nulle.
C'est pourquoi le déréférencement d'un pointeur nul et d'une référence nulle produit la même exception.
Et le deuxième point? Le déréférencement de tout pointeur non valide qui tombe dans la page la plus basse de la mémoire virtuelle provoque la même erreur du système d'exploitation, et donc la même exception.
Pourquoi est-ce logique? Supposons que nous ayons une structure contenant deux entrées et un pointeur non géré égal à null. Si nous essayons de déréférencer le deuxième entier dans la structure, le CLR
ne tentera pas d'accéder au stockage à l'emplacement zéro; il accédera au stockage à l'emplacement quatre. Mais logiquement, c'est une déréférence nulle parce que nous arrivons à cette adresse via la valeur nulle.
Si vous travaillez avec du code dangereux et que vous obtenez une exception de déréférence nulle, sachez simplement que le pointeur incriminé n'a pas besoin d'être nul. Il peut s'agir de n'importe quel emplacement dans la page la plus basse et cette exception sera produite.
new Book { Author = { Age = 45 } };
Comment l'initialisation interne fonctionne-t-elle même ... Je ne peux pas penser à une situation où l'init interne fonctionnerait jamais, mais il compile et l'intellisense fonctionne ... Sauf pour les structures?
Le NullReference Exception
pour Visual Basic n'est pas différent de celui en C # . Après tout, ils signalent tous deux la même exception définie dans le .NET Framework qu'ils utilisent tous les deux. Les causes propres à Visual Basic sont rares (peut-être une seule).
Cette réponse utilisera les termes, la syntaxe et le contexte Visual Basic. Les exemples utilisés proviennent d'un grand nombre de questions sur le débordement de pile passées. Il s'agit de maximiser la pertinence en utilisant les types de situations souvent vues dans les publications. Un peu plus d'explications sont également fournies pour ceux qui pourraient en avoir besoin. Un exemple similaire au vôtre est très probablement répertorié ici.
Remarque:
NullReferenceException
(NRE), comment le trouver, comment le réparer et comment l'éviter. Un NRE peut être causé de plusieurs façons, il est donc peu probable que ce soit votre seule rencontre.Le message "Objet non défini sur une instance d'Objet" signifie que vous essayez d'utiliser un objet qui n'a pas été initialisé. Cela se résume à l'un d'eux:
Puisque le problème est une référence d'objet qui est Nothing
, la réponse est de les examiner pour trouver lequel. Déterminez ensuite pourquoi il n'est pas initialisé. Maintenez la souris sur les différentes variables et Visual Studio (VS) affichera leurs valeurs - le coupable sera Nothing
.
Vous devez également supprimer tous les blocs Try / Catch du code pertinent, en particulier ceux où il n'y a rien dans le bloc Catch. Cela provoquera le plantage de votre code lorsqu'il essaie d'utiliser un objet qui l'est Nothing
. C'est ce que vous voulez car il identifiera l' emplacement exact du problème et vous permettra d'identifier l'objet à l'origine de ce problème.
Un MsgBox
in the Catch qui s'affiche Error while...
ne sera d'aucune utilité. Cette méthode conduit également à de très mauvaises questions de débordement de pile, car vous ne pouvez pas décrire l'exception réelle, l'objet impliqué ou même la ligne de code où elle se produit.
Vous pouvez également utiliser le Locals Window
( Débogage -> Windows -> Locaux ) pour examiner vos objets.
Une fois que vous savez quel est et où est le problème, il est généralement assez facile à résoudre et plus rapide que de poster une nouvelle question.
Voir également:
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Le problème est qu'il Dim
ne crée pas d' objet CashRegister ; il déclare uniquement une variable nommée reg
de ce type. La déclaration d' une variable d'objet et la création d'une instance sont deux choses différentes.
Remède
L' New
opérateur peut souvent être utilisé pour créer l'instance lorsque vous la déclarez:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Lorsqu'il ne convient que de créer l'instance ultérieurement:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Remarque: Ne réutilisez Dim
pas dans une procédure, y compris le constructeur ( Sub New
):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
Cela va créer une variable localereg
, qui n'existe que dans ce contexte (sub). La reg
variable de niveau module Scope
que vous utiliserez partout ailleurs reste Nothing
.
L'
New
opérateur manquant est la cause n ° 1 desNullReference Exceptions
problèmes de débordement de pile examinés.Visual Basic essaie de rendre le processus clair à plusieurs reprises en utilisant
New
: L'utilisation de l'New
opérateur crée un nouvel objet et appelleSub New
- le constructeur - où votre objet peut effectuer toute autre initialisation.
Pour être clair, Dim
(ou Private
) ne déclare qu'une variable et son Type
. L' étendue de la variable - qu'elle existe pour l'ensemble du module / de la classe ou qu'elle soit locale à une procédure - est déterminée par l' endroit où elle est déclarée. Private | Friend | Public
définit le niveau d'accès, pas la portée .
Pour plus d'informations, voir:
Les tableaux doivent également être instanciés:
Private arr as String()
Ce tableau a seulement été déclaré, pas créé. Il existe plusieurs façons d'initialiser un tableau:
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) {}
Remarque: à partir de VS 2010, lors de l'initialisation d'un tableau local à l'aide d'un littéral et Option Infer
, les éléments As <Type>
et New
sont facultatifs:
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}
Le type de données et la taille du tableau sont déduits des données attribuées. Les déclarations de niveau de classe / module nécessitent toujours As <Type>
avec Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Exemple: tableau d'objets de classe
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
Le tableau a été créé, mais pas les Foo
objets qu'il contient .
Remède
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Utiliser un List(Of T)
rendra assez difficile d'avoir un élément sans objet valide:
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
Pour plus d'informations, voir:
Les collections .NET (dont il existe de nombreuses variétés - listes, dictionnaire, etc.) doivent également être instanciées ou créées.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
Vous obtenez la même exception pour la même raison - myList
n'a été déclaré, mais aucune instance n'a été créée. Le remède est le même:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
Un oubli commun est une classe qui utilise une collection 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
L'une ou l'autre procédure se traduira par un NRE, car il barList
est uniquement déclaré, et non instancié. La création d'une instance de Foo
ne créera pas également une instance de l'interne barList
. C'était peut-être l'intention de le faire dans le constructeur:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Comme précédemment, c'est incorrect:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Pour plus d'informations, voir List(Of T)
Classe .
Travailler avec des bases de données présente de nombreuses possibilités pour une NullReference car il peut y avoir de nombreux objets ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) en usage à la fois. Remarque: Peu importe le fournisseur de données que vous utilisez - MySQL, SQL Server, OleDB, etc. - les concepts sont les mêmes.
Exemple 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
Comme précédemment, l' ds
objet Dataset a été déclaré, mais aucune instance n'a été créée. Le DataAdapter
remplira un existant DataSet
, pas en créer un. Dans ce cas, puisqu'il ds
s'agit d'une variable locale, l'EDI vous avertit que cela peut se produire:
Lorsqu'il est déclaré en tant que variable de niveau module / classe, comme cela semble être le cas con
, le compilateur ne peut pas savoir si l'objet a été créé par une procédure en amont. N'ignorez pas les avertissements.
Remède
Dim ds As New DataSet
Exemple 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)
Une faute de frappe est un problème ici: Employees
vs Employee
. Aucun DataTable
"employé" n'a été créé, donc un NullReferenceException
résultat a tenté d'y accéder. Un autre problème potentiel est de supposer qu'il y en aura, ce Items
qui peut ne pas être le cas lorsque le SQL inclut une clause WHERE.
Remède
Comme cela utilise une seule table, l'utilisation Tables(0)
évitera les fautes d'orthographe. L'examen Rows.Count
peut également aider:
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
est une fonction renvoyant le nombre de personnes Rows
affectées qui peut également être testée:
If da.Fill(ds, "Employees") > 0 Then...
Exemple 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
Le DataAdapter
fournira TableNames
comme indiqué dans l'exemple précédent, mais il n'analyse pas les noms de la table SQL ou de la base de données. Par conséquent, ds.Tables("TICKET_RESERVATION")
référence une table inexistante.
Le remède est le même, référencez le tableau par index:
If ds.Tables(0).Rows.Count > 0 Then
Voir aussi Classe DataTable .
If myFoo.Bar.Items IsNot Nothing Then
...
Le code ne teste Items
que les deux myFoo
et Bar
peut également être Nothing. Le remède consiste à tester la chaîne ou le chemin complet des objets un par un:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
est important. Les tests suivants ne seront pas effectués une fois la première False
condition rencontrée. Cela permet au code de «percer» en toute sécurité dans le (s) objet (s) un «niveau» à la fois, en évaluant myFoo.Bar
uniquement après (et si) myFoo
est déterminé comme étant valide. Les chaînes ou chemins d'objets peuvent devenir assez longs lors du codage d'objets complexes:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Il n'est pas possible de référencer quoi que ce soit «en aval» d'un null
objet. Cela s'applique également aux contrôles:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Ici, myWebBrowser
ou Document
pourrait être Nothing ou l' formfld1
élément peut ne pas exister.
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 autres choses, ce code ne prévoit pas que l'utilisateur n'a peut-être pas sélectionné quelque chose dans un ou plusieurs contrôles d'interface utilisateur. ListBox1.SelectedItem
pourrait bien être Nothing
, il ListBox1.SelectedItem.ToString
en résultera un NRE.
Remède
Validez les données avant de les utiliser (utilisez également Option Strict
les paramètres SQL et 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
Vous pouvez également utiliser (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
Il s'agit d'un moyen assez courant d'obtenir un NRE. En C #, selon la façon dont il est codé, l'EDI signalera qu'il Controls
n'existe pas dans le contexte actuel ou "ne peut pas référencer un membre non statique". Donc, dans une certaine mesure, c'est une situation uniquement VB. Il est également complexe car il peut entraîner une cascade de pannes.
Les tableaux et les collections ne peuvent pas être initialisés de cette façon. Ce code d'initialisation s'exécutera avant que le constructeur ne crée le Form
ou le Controls
. Par conséquent:
somevar
affectation entraînera un NRE immédiat car rien n'a de .Text
propriétéRéférencer les éléments du tableau ultérieurement entraînera un NRE. Si vous le faites dans Form_Load
, en raison d'un bogue étrange, l'EDI peut ne pas signaler l'exception lorsqu'elle se produit. L'exception apparaîtra plus tard lorsque votre code essaie d'utiliser le tableau. Cette "exception silencieuse" est détaillée dans cet article . Pour nos besoins, la clé est que lorsque quelque chose de catastrophique se produit lors de la création d'un formulaire ( Sub New
ou d'un Form Load
événement), les exceptions peuvent ne pas être signalées, le code quitte la procédure et affiche simplement le formulaire.
Puisqu'aucun autre code dans votre événement Sub New
ou Form Load
ne s'exécutera après le NRE, de nombreuses autres choses peuvent être laissées non initialisées.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Notez que cela s'applique à toutes les références de contrôle et de composant qui les rendent illégales où elles se trouvent:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Remède partiel
Il est curieux que VB ne fournit pas un avertissement, mais le remède est de déclarer les conteneurs au niveau de la forme, mais initialiser les dans le gestionnaire d'événement de chargement de formulaire lorsque les contrôles font exist. Cela peut être fait Sub New
tant que votre code est après l' InitializeComponent
appel:
' 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
Le code du tableau n'est peut-être pas encore sorti du bois. Tous les contrôles qui sont dans un contrôle conteneur (comme un GroupBox
ou Panel
) ne seront pas trouvés dans Me.Controls
; ils seront dans la collection Controls de ce Panel ou GroupBox. Un contrôle ne sera pas non plus renvoyé lorsque le nom du contrôle est mal orthographié ( "TeStBox2"
). Dans de tels cas, Nothing
sera à nouveau stocké dans ces éléments du tableau et un NRE sera généré lorsque vous tenterez de le référencer.
Ceux-ci devraient être faciles à trouver maintenant que vous savez ce que vous recherchez:
"Button2" réside sur un Panel
Remède
Plutôt que des références indirectes par nom à l'aide de la Controls
collection du formulaire , utilisez la référence de contrôle:
' 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
Il s'agit d'un cas où l'EDI vous avertira que « tous les chemins ne renvoient pas une valeur et NullReferenceException
peuvent en résulter ». Vous pouvez supprimer l'avertissement, en le remplaçant Exit Function
par Return Nothing
, mais cela ne résout pas le problème. Tout ce qui tente d'utiliser le retour someCondition = False
entraînera un NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Remède
Remplacez Exit Function
la fonction par Return bList
. Retourner un vide List
n'est pas la même chose que retourner Nothing
. S'il y a une chance qu'un objet retourné puisse l'être Nothing
, testez avant de l'utiliser:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Un Try / Catch mal implémenté peut cacher où se trouve le problème et en entraîner de nouveaux:
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
Il s'agit d'un cas où un objet n'est pas créé comme prévu, mais démontre également la contre-utilité d'un vide Catch
.
Il y a une virgule supplémentaire dans le SQL (après 'mailaddress') qui entraîne une exception à .ExecuteReader
. Après que le Catch
ne fait rien, Finally
essaie d'effectuer un nettoyage, mais comme vous ne pouvez pas Close
un DataReader
objet nul , un tout nouveau NullReferenceException
résultat.
Un Catch
bloc vide est le terrain de jeu du diable. Cet OP était perplexe de savoir pourquoi il obtenait un NRE dans le Finally
bloc. Dans d'autres situations, un vide Catch
peut entraîner quelque chose d'autre beaucoup plus en aval en se détraquant et vous faire passer du temps à regarder les mauvaises choses au mauvais endroit pour le problème. (L '"exception silencieuse" décrite ci-dessus offre la même valeur de divertissement.)
Remède
N'utilisez pas de blocs Try / Catch vides - laissez le code se bloquer afin que vous puissiez a) identifier la cause b) identifier l'emplacement et c) appliquer un remède approprié. Les blocs Try / Catch ne sont pas destinés à masquer les exceptions à la personne uniquement qualifiée pour les corriger - le développeur.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
La IsDBNull
fonction est utilisée pour tester si une valeur est égale à System.DBNull
: De MSDN:
La valeur System.DBNull indique que l'objet représente des données manquantes ou inexistantes. DBNull n'est pas identique à Nothing, ce qui indique qu'une variable n'a pas encore été initialisée.
Remède
If row.Cells(0) IsNot Nothing Then ...
Comme précédemment, vous pouvez tester Rien, puis une valeur spécifique:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Exemple 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
renvoie le premier élément ou la valeur par défaut, qui est Nothing
pour les types de référence et jamais 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 un CheckBox
avec chkName
est introuvable (ou existe dans un GroupBox
), alors chk
sera Nothing et toute tentative de référence à une propriété entraînera une exception.
Remède
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
La DGV a quelques caprices vues périodiquement:
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
a AutoGenerateColumns = True
, il va créer les colonnes, mais il ne les nomme pas, de sorte que le code ci - dessus échoue lorsqu'il y fait référence par son nom.
Remède
Nommez les colonnes manuellement ou référencez par index:
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
Lorsque votre DataGridView
a AllowUserToAddRows
comme True
valeur par défaut, le Cells
dans la ligne vierge / nouvelle en bas contiendra tous Nothing
. La plupart des tentatives d'utilisation du contenu (par exemple ToString
) entraîneront un NRE.
Remède
Utilisez une For/Each
boucle et testez la IsNewRow
propriété pour déterminer s'il s'agit de cette dernière ligne. Cela fonctionne, que ce AllowUserToAddRows
soit vrai ou non:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Si vous utilisez une For n
boucle, modifier le nombre de lignes ou de l' utilisation Exit For
quand IsNewRow
est vrai.
Dans certaines circonstances, essayer d'utiliser un élément My.Settings
dont est un StringCollection
peut entraîner une NullReference la première fois que vous l'utilisez. La solution est la même, mais pas aussi évidente. Considérer:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Étant donné que VB gère les paramètres pour vous, il est raisonnable de s'attendre à ce qu'il initialise la collection. Il le sera, mais uniquement si vous avez précédemment ajouté une entrée initiale à la collection (dans l'éditeur de paramètres). Étant donné que la collection est (apparemment) initialisée lorsqu'un élément est ajouté, elle reste Nothing
lorsqu'il n'y a aucun élément dans l'éditeur de paramètres à ajouter.
Remède
Initialisez la collection de paramètres dans le Load
gestionnaire d'événements du formulaire , si / quand nécessaire:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
En règle générale, la Settings
collection ne devra être initialisée que lors de la première exécution de l'application. Un autre remède consiste à ajouter une valeur initiale à votre collection dans Projet -> Paramètres | FooBars , enregistrez le projet, puis supprimez la fausse valeur.
Vous avez probablement oublié l' New
opérateur.
ou
Quelque chose que vous supposiez fonctionnerait parfaitement pour retourner un objet initialisé à votre code, ne l'a pas fait.
N'ignorez (jamais) les avertissements du compilateur et utilisez Option Strict On
(toujours).
Un autre scénario consiste à convertir un objet nul en un type de valeur . Par exemple, le code ci-dessous:
object o = null;
DateTime d = (DateTime)o;
Il jettera un NullReferenceException
sur le casting. Cela semble assez évident dans l'exemple ci-dessus, mais cela peut se produire dans des scénarios complexes plus "à liaison tardive" où l'objet nul a été renvoyé à partir d'un code que vous ne possédez pas, et le transtypage est par exemple généré par un système automatique.
Un exemple de ceci est ce simple fragment de liaison ASP.NET avec le contrôle Calendar:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Ici, il SelectedDate
s'agit en fait d'une propriété - de DateTime
type - du Calendar
type Contrôle Web, et la liaison pourrait parfaitement renvoyer quelque chose de nul. Le générateur implicite ASP.NET créera un morceau de code qui sera équivalent au code cast ci-dessus. Et cela soulèvera un NullReferenceException
problème assez difficile à repérer, car il se trouve dans du code généré par ASP.NET qui compile très bien ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Cela signifie que la variable en question ne pointe vers rien. Je pourrais générer ceci comme ceci:
SqlConnection connection = null;
connection.Open();
Cela lèvera l'erreur parce que même si j'ai déclaré la variable " connection
", elle n'est pointée vers rien. Lorsque j'essaie d'appeler le membre " Open
", il n'y a aucune référence à résoudre et cela générera l'erreur.
Pour éviter cette erreur:
object == null
.L'outil Resharper de JetBrains identifiera chaque endroit dans votre code qui a la possibilité d'une erreur de référence nulle, vous permettant de mettre une vérification nulle. Cette erreur est la première source de bogues, à mon humble avis.
Cela signifie que votre code a utilisé une variable de référence d'objet définie sur null (c'est-à-dire qu'il ne faisait pas référence à une instance d'objet réelle).
Pour éviter l'erreur, les objets qui pourraient être nuls doivent être testés pour null avant d'être utilisés.
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
}
Sachez que quel que soit le scénario, la cause est toujours la même dans .NET:
Vous essayez d'utiliser une variable de référence dont la valeur est
Nothing
/null
. Lorsque la valeur estNothing
/null
pour la variable de référence, cela signifie qu'elle ne contient pas réellement de référence à une instance d'un objet qui existe sur le tas.Soit vous n'avez jamais affecté quelque chose à la variable, vous n'avez jamais créé d'instance de la valeur affectée à la variable, soit vous définissez la variable égale à
Nothing
/null
manuellement, soit vous avez appelé une fonction qui définit la variable surNothing
/null
pour vous.
Un exemple de cette exception levée est: Lorsque vous essayez de vérifier quelque chose, c'est null.
Par exemple:
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
}
Le runtime .NET lève une exception NullReferenceException lorsque vous essayez d'effectuer une action sur quelque chose qui n'a pas été instancié, c'est-à-dire le code ci-dessus.
Par rapport à une ArgumentNullException qui est généralement levée comme mesure défensive si une méthode s'attend à ce que ce qui lui est transmis ne soit pas nul.
Plus d'informations sont dans C # NullReferenceException et Null Parameter .
Mise à jour C # 8.0, 2019: types de référence nullables
C # 8.0 introduit des types de référence nullables et des types de référence non nullables . Par conséquent, seuls les types de référence nullables doivent être vérifiés pour éviter une exception NullReferenceException .
Si vous n'avez pas initialisé un type de référence et que vous souhaitez définir ou lire l'une de ses propriétés, il lèvera une exception NullReferenceException .
Exemple:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Vous pouvez simplement éviter cela en vérifiant si la variable n'est pas nulle:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Pour bien comprendre pourquoi une exception NullReferenceException est levée, il est important de connaître la différence entre les types de valeur et les [types de référence] [3].
Donc, si vous avez affaire à des types de valeur , NullReferenceExceptions ne peut pas se produire. Cependant, vous devez rester vigilant lorsque vous traitez avec des types de référence !
Seuls les types de référence, comme son nom l'indique, peuvent contenir des références ou pointer littéralement vers rien (ou «null»). Alors que les types de valeur contiennent toujours une valeur.
Types de référence (ceux-ci doivent être vérifiés):
Types de valeurs (vous pouvez simplement ignorer ceux-ci):
Un autre cas où NullReferenceExceptions
cela peut se produire est l'utilisation (incorrecte) de l' as
opérateur :
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
Ici, Book
et Car
sont des types incompatibles; a Car
ne peut pas être converti / converti en a Book
. Lorsque cette conversion échoue, as
revient null
. L'utilisation mybook
après cela provoque a NullReferenceException
.
En général, vous devez utiliser un cast ou as
, comme suit:
Si vous vous attendez à ce que la conversion de type réussisse toujours (c'est-à-dire que vous savez ce que l'objet devrait être à l'avance), alors vous devez utiliser un transtypage:
ComicBook cb = (ComicBook)specificBook;
Si vous n'êtes pas sûr du type, mais que vous souhaitez essayer de l'utiliser comme type spécifique, utilisez as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Vous utilisez l'objet qui contient la référence de valeur nulle. Il s'agit donc de donner une exception nulle. Dans l'exemple, la valeur de chaîne est nulle et lors de la vérification de sa longueur, l'exception s'est produite.
Exemple:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
L'erreur d'exception est:
Exception non-gérée:
System.NullReferenceException: référence d'objet non définie sur une instance d'un objet. à Program.Main ()
Bien que ce qui provoque une NullReferenceExceptions et des approches pour éviter / corriger une telle exception ait été abordé dans d'autres réponses, ce que de nombreux programmeurs n'ont pas encore appris, c'est comment déboguer indépendamment ces exceptions pendant le développement.
Dans Visual Studio, cela est généralement facile grâce au débogueur Visual Studio .
Tout d'abord, assurez-vous que l'erreur correcte sera détectée - voir Comment puis-je autoriser la rupture sur 'System.NullReferenceException' dans VS2010? Remarque 1
Ensuite, commencez avec le débogage (F5) ou attachez [le débogueur VS] au processus en cours d'exécution . À l'occasion, il peut être utile de l'utiliser Debugger.Break
, ce qui vous demandera de lancer le débogueur.
À présent, lorsque l'exception NullReferenceException est levée (ou non gérée), le débogueur s'arrête (rappelez-vous la règle définie ci-dessus?) Sur la ligne sur laquelle l'exception s'est produite. Parfois, l'erreur sera facile à repérer.
Par exemple, dans la ligne suivante, le seul code qui peut provoquer l'exception est if myString
s'évalue à null. Cela peut être vérifié en regardant la fenêtre de surveillance ou en exécutant des expressions dans la fenêtre immédiate .
var x = myString.Trim();
Dans les cas plus avancés, tels que les suivants, vous devrez utiliser l'une des techniques ci-dessus (Windows Watch ou Immédiat) pour inspecter les expressions afin de déterminer si str1
était nul ou str2
non.
var x = str1.Trim() + str2.Trim();
Une fois que l'exception a été repérée, il est généralement inutile de raisonner à l'envers pour savoir où la valeur nulle a été [incorrectement] introduite -
Prenez le temps nécessaire pour comprendre la cause de l'exception. Inspectez les expressions nulles. Inspectez les expressions précédentes qui auraient pu entraîner de telles expressions nulles. Ajoutez des points d'arrêt et parcourez le programme selon les besoins. Utilisez le débogueur.
1 Si Break on Throws est trop agressif et que le débogueur s'arrête sur un NPE dans la bibliothèque .NET ou tierce, Break on User-Unhandled peut être utilisé pour limiter les exceptions interceptées. De plus, VS2012 présente Just My Code que je recommande également d'activer.
Si vous déboguez avec Just My Code activé, le comportement est légèrement différent. Lorsque Just My Code est activé, le débogueur ignore les exceptions CLR (Common Language Runtime) de première chance qui sont levées en dehors de My Code et ne passent pas par My Code.
Simon Mourier a donné cet exemple :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
où une conversion unboxing (cast) de object
(ou de l'une des classes System.ValueType
ou System.Enum
, ou d'un type d'interface) en un type de valeur (autre que Nullable<>
) en soi donne le NullReferenceException
.
Dans l'autre sens, une boxe conversion d' un Nullable<>
qui a HasValue
égal false
à un type de référence, peut donner une null
référence qui peut alors conduire plus tard à un NullReferenceException
. L'exemple classique est:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Parfois, la boxe se déroule d'une autre manière. Par exemple avec cette méthode d'extension non générique:
public static void MyExtension(this object x)
{
x.ToString();
}
le code suivant sera problématique:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Ces cas surviennent en raison des règles spéciales que le runtime utilise lors de la boxe des Nullable<>
instances.
Ajout d'un cas lorsque le nom de classe pour l'entité utilisée dans le cadre d'entité est identique au nom de classe pour un fichier code-behind de formulaire Web.
Supposons que vous ayez un formulaire Web Contact.aspx dont la classe codebehind est Contact et que vous ayez un nom d'entité Contact.
Ensuite, le code suivant lèvera une exception NullReferenceException lorsque vous appelez context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Par souci d'exhaustivité, classe DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
et Classe d'entité de contact. Parfois, les classes d'entités sont des classes partielles afin que vous puissiez également les étendre dans d'autres fichiers.
public partial class Contact
{
public string Name {get; set;}
}
L'erreur se produit lorsque l'entité et la classe codebehind se trouvent dans le même espace de noms. Pour résoudre ce problème, renommez la classe d'entité ou la classe codebehind pour Contact.aspx.
Raison Je ne suis toujours pas sûr de la raison. Mais chaque fois que l'une des classes d'entité étendra System.Web.UI.Page, cette erreur se produit.
Pour la discussion, jetez un œil à NullReferenceException dans DbContext.saveChanges ()
Un autre cas général où l'on pourrait recevoir cette exception concerne les classes de simulation pendant les tests unitaires. Quel que soit le cadre de simulation utilisé, vous devez vous assurer que tous les niveaux appropriés de la hiérarchie des classes sont correctement simulés. En particulier, toutes les propriétés HttpContext
référencées par le code sous test doivent être moquées.
Voir « NullReferenceException levée lors du test de AuthorizationAttribute personnalisé » pour un exemple quelque peu détaillé.
J'ai une perspective différente pour répondre à cela. Ce genre de réponses "que puis-je faire d'autre pour l'éviter? "
Lorsque vous travaillez sur différentes couches , par exemple dans une application MVC, un contrôleur a besoin de services pour appeler des opérations commerciales. Dans de tels scénarios, le conteneur d'injection de dépendances peut être utilisé pour initialiser les services afin d'éviter l' exception NullReferenceException . Cela signifie donc que vous n'avez pas à vous soucier de vérifier la valeur null et d'appeler simplement les services à partir du contrôleur comme s'ils seraient toujours disponibles (et initialisés) en tant que singleton ou prototype.
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 ce qui concerne "que dois-je faire" , il peut y avoir de nombreuses réponses.
Une manière plus "formelle" d'empêcher de telles conditions d'erreur lors du développement consiste à appliquer la conception par contrat dans votre code. Cela signifie que vous devez définir des invariants de classe , et / ou même des préconditions et postconditions de fonction / méthode sur votre système, lors du développement.
En bref, les invariants de classe garantissent qu'il y aura des contraintes dans votre classe qui ne seront pas violées en utilisation normale (et par conséquent, la classe ne se mettra pas dans un état incohérent). Les conditions préalables signifient que les données fournies en entrée à une fonction / méthode doivent suivre un ensemble de contraintes et ne jamais les violer, et les post - conditions signifient qu'une sortie de fonction / méthode doit à nouveau suivre les contraintes définies sans jamais les violer. Les conditions du contrat ne doivent jamais être violées lors de l'exécution d'un programme sans bogue, donc la conception par contrat est vérifiée en pratique en mode débogage, tout en étant désactivée dans les versions , pour maximiser les performances du système développé.
De cette façon, vous pouvez éviter les NullReferenceException
cas qui résultent d'une violation de l'ensemble de contraintes. Par exemple, si vous utilisez une propriété d'objet X
dans une classe et essayez ultérieurement d'invoquer l'une de ses méthodes et X
que sa valeur est nulle, cela entraînera NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Mais si vous définissez «la propriété X ne doit jamais avoir de valeur nulle» comme condition préalable à la méthode, vous pouvez empêcher le scénario décrit précédemment:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Pour cette raison, le projet Code Contracts existe pour les applications .NET.
Alternativement, la conception par contrat peut être appliquée à l'aide d' assertions .
MISE À JOUR: Il convient de mentionner que le terme a été inventé par Bertrand Meyer dans le cadre de sa conception du langage de programmation Eiffel .
Un NullReferenceException
est levé lorsque nous essayons d'accéder aux propriétés d'un objet nul ou lorsqu'une valeur de chaîne devient vide et que nous essayons d'accéder aux méthodes de chaîne.
Par exemple:
Lorsqu'une méthode de chaîne d'une chaîne vide accède:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Lorsqu'une propriété d'un objet nul accède:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
ne lèvera pas d'exception de référence nulle. Il représente une chaîne réelle, bien que vide (c'est-à-dire ""
). Puisqu'il a un objet à appeler ToLower()
, il ne serait pas logique d'y lancer une exception de référence nulle.
TL; DR: essayez d'utiliser Html.Partial
au lieu deRenderpage
J'obtenais Object reference not set to an instance of an object
quand j'ai essayé de rendre une vue dans une vue en lui envoyant un modèle, comme ceci:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Le débogage a montré que le modèle était Null dans MyOtherView. Jusqu'à ce que je le change:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Et ça a marché.
De plus, la raison pour laquelle je n'avais pas Html.Partial
à commencer était parce que Visual Studio lançait parfois des lignes ondulées ressemblant à des erreurs Html.Partial
s'il se trouvait dans une foreach
boucle de construction différente , même si ce n'est pas vraiment une erreur:
@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>
Mais j'ai pu exécuter l'application sans problème avec cette "erreur". J'ai pu me débarrasser de l'erreur en modifiant la structure de la foreach
boucle pour ressembler à ceci:
@foreach(var M in MyEntities){
...
}
Bien que j'ai le sentiment que c'était parce que Visual Studio lisait mal les esperluettes et les crochets.
Html.Partial
, pas@Html.Partial
Null
), donc je savais que l'erreur concernait la façon dont
Que peux-tu y faire?
Il y a beaucoup de bonnes réponses ici expliquant ce qu'est une référence nulle et comment la déboguer. Mais il y a très peu de moyens de prévenir le problème ou du moins de le rendre plus facile à attraper.
Vérifier les arguments
Par exemple, les méthodes peuvent vérifier les différents arguments pour voir s'ils sont nuls et lever un ArgumentNullException
, une exception évidemment créée dans ce but précis.
Le constructeur de ArgumentNullException
even prend le nom du paramètre et un message comme arguments afin que vous puissiez dire exactement au développeur quel est le problème.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Utiliser des outils
Il existe également plusieurs bibliothèques qui peuvent vous aider. "Resharper" par exemple peut vous fournir des avertissements pendant que vous écrivez du code, surtout si vous utilisez leur attribut: NotNullAttribute
Il y a "Microsoft Code Contracts" où vous utilisez une syntaxe comme celle Contract.Requires(obj != null)
qui vous donne l'exécution et la vérification de la compilation: Présentation de Code Contracts .
Il y a aussi "PostSharp" qui vous permettra d'utiliser simplement des attributs comme celui-ci:
public void DoSometing([NotNull] obj)
En faisant cela et en faisant de PostSharp une partie de votre processus de construction, la valeur obj
null sera vérifiée lors de l'exécution. Voir: PostSharp null check
Solution de code simple
Ou vous pouvez toujours coder votre propre approche en utilisant de l'ancien code. Par exemple, voici une structure que vous pouvez utiliser pour intercepter des références nulles. Il s'inspire du même concept 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 };
}
}
Vous utiliseriez très similaire à la même manière que vous utiliseriez Nullable<T>
, sauf dans le but d'accomplir exactement le contraire - de ne pas permettre null
. Voici quelques exemples:
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 implicitement casté vers et depuis T
afin que vous puissiez l'utiliser presque partout où vous en avez besoin. Par exemple, vous pouvez passer un Person
objet à une méthode qui prend NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Comme vous pouvez le voir ci-dessus, comme avec nullable, vous accéderez à la valeur sous-jacente via la Value
propriété. Alternativement, vous pouvez utiliser une distribution explicite ou implicite, vous pouvez voir un exemple avec la valeur de retour ci-dessous:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Ou vous pouvez même l'utiliser lorsque la méthode revient T
(dans ce cas Person
) en faisant un cast. Par exemple, le code suivant aimerait juste le code ci-dessus:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combinez avec l'extension
Combinez NotNull<T>
avec une méthode d'extension et vous pouvez couvrir encore plus de situations. Voici un exemple de ce à quoi peut ressembler la méthode d'extension:
[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;
}
}
Et voici un exemple de la façon dont il pourrait être utilisé:
var person = GetPerson().NotNull();
GitHub
Pour votre référence, j'ai rendu le code ci-dessus disponible sur GitHub, vous pouvez le trouver sur:
https://github.com/luisperezphd/NotNull
Fonction de langue associée
C # 6.0 a introduit "l'opérateur null-conditionnel" qui aide un peu à cela. Avec cette fonctionnalité, vous pouvez référencer des objets imbriqués et si l'un d'eux est null
l'expression entière retourne null
.
Cela réduit le nombre de contrôles nuls que vous devez effectuer dans certains cas. La syntaxe consiste à mettre un point d'interrogation avant chaque point. Prenons l'exemple du code suivant:
var address = country?.State?.County?.City;
Imaginez que country
c'est un objet de type Country
qui a une propriété appelée State
et ainsi de suite. Si country
, State
, County
ou City
est null
alors address will be
nulle . Therefore you only have to check whether
adresse is
null`.
C'est une excellente fonctionnalité, mais elle vous donne moins d'informations. Cela ne rend pas évident lequel des 4 est nul.
Intégré comme Nullable?
C # a un joli raccourci pour Nullable<T>
, vous pouvez rendre quelque chose nullable en mettant un point d'interrogation après le type comme ça int?
.
Ce serait bien si C # avait quelque chose comme le NotNull<T>
struct ci - dessus et avait un raccourci similaire, peut - être le point d'exclamation pour que vous puissiez écrire quelque chose comme (!): public void WriteName(Person! person)
.
Fait intéressant, aucune des réponses sur cette page ne mentionne les deux cas de bord, j'espère que personne ne m'en voudra si je les ajoute:
Les dictionnaires génériques dans .NET ne sont pas adaptés aux threads et ils peuvent parfois générer un NullReference
ou même (plus fréquemment) un KeyNotFoundException
lorsque vous essayez d'accéder à une clé à partir de deux threads simultanés. L'exception est assez trompeuse dans ce cas.
Si un NullReferenceException
est généré par du unsafe
code, vous pouvez regarder vos variables de pointeur et les vérifier IntPtr.Zero
ou quelque chose. C'est la même chose ("exception de pointeur nul"), mais dans un code dangereux, les variables sont souvent transtypées en types de valeur / tableaux, etc., et vous vous cognez la tête contre le mur, en vous demandant comment un type de valeur peut jeter ceci exception.
(Une autre raison de ne pas utiliser de code dangereux, sauf si vous en avez besoin, en passant)
null
quelle manière?
Vous pouvez corriger NullReferenceException de manière propre en utilisant des opérateurs Null-conditionnels en c # 6 et écrire moins de code pour gérer les vérifications nulles.
Il est utilisé pour tester null avant d'effectuer une opération d'accès aux membres (?.) Ou d'index (? [).
Exemple
var name = p?.Spouse?.FirstName;
est équivalent à:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
Le résultat est que le nom sera nul lorsque p est nul ou lorsque p.Spouse est nul.
Sinon, le nom de la variable se verra attribuer la valeur de p.Spouse.FirstName.
Pour plus de détails: opérateurs null-conditionnels
La ligne d'erreur "Référence d'objet non définie sur une instance d'un objet." Indique que vous n'avez pas affecté d'objet d'instance à une référence d'objet et que vous accédez toujours aux propriétés / méthodes de cet objet.
par exemple: disons que vous avez une classe appelée myClass et qu'elle contient une propriété prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Maintenant, vous accédez à ce prop1 dans une autre classe comme ci-dessous:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
la ligne ci-dessus génère une erreur car la référence de la classe myClass est déclarée mais pas instanciée ou une instance d'objet n'est pas affectée à la référence de cette classe.
Pour résoudre ce problème, vous devez instancier (attribuer un objet à la référence de cette classe).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
NullReferenceException ou Référence d'objet non définie sur une instance d'un objet se produit lorsqu'un objet de la classe que vous essayez d'utiliser n'est pas instancié. Par exemple:
Supposons que vous ayez une classe nommée Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Maintenant, considérez une autre classe où vous essayez de récupérer le nom complet de l'élève.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Comme vu dans le code ci-dessus, l'instruction Student s - déclare uniquement la variable de type Student, notez que la classe Student n'est pas instanciée à ce stade. Par conséquent, lorsque l'instruction s.GetFullName () est exécutée, elle lèvera l'exception NullReferenceException.
Eh bien, en termes simples:
Vous essayez d'accéder à un objet qui n'est pas créé ou qui n'est pas actuellement en mémoire.
Alors, comment y faire face:
Déboguez et laissez le débogueur s'arrêter ... Cela vous amènera directement à la variable qui est cassée ... Maintenant, votre tâche est de simplement corriger cela .. En utilisant le nouveau mot-clé à l'endroit approprié.
Si cela est dû à certaines commandes de base de données parce que l'objet n'est pas présent, tout ce que vous avez à faire est de faire une vérification nulle et de le gérer:
if (i == null) {
// Handle this
}
Le plus difficile .. si le GC a déjà collecté l'objet ... Cela se produit généralement si vous essayez de trouver un objet à l'aide de chaînes ... Autrement dit, en le trouvant par le nom de l'objet, il peut arriver que le GC soit déjà nettoyé ... C'est difficile à trouver et deviendra un problème ... Une meilleure façon de résoudre ce problème est de faire des vérifications nulles partout où cela est nécessaire pendant le processus de développement. Cela vous fera gagner beaucoup de temps.
En recherchant par nom, je veux dire qu'un cadre vous permet de FIndObjects en utilisant des chaînes et le code pourrait ressembler à ceci: FindObject ("ObjectName");
Littéralement, la façon la plus simple de corriger une NullReferenceExeption a deux façons. Si vous avez un GameObject par exemple avec un script attaché et une variable nommée rb (rigidbody), cette variable commencera nulle lorsque vous démarrez votre jeu.
C'est pourquoi vous obtenez une NullReferenceExeption car l'ordinateur n'a pas de données stockées dans cette variable.
Je vais utiliser une variable RigidBody comme exemple.
Nous pouvons ajouter des données très facilement de plusieurs manières:
rb = GetComponent<Rigidbody>();
Start()
ou Awake()
. rb = AddComponent<RigidBody>();
Notes supplémentaires: Si vous voulez que l'unité ajoute un composant à votre objet et que vous ayez oublié d'en ajouter un, vous pouvez taper [RequireComponent(typeof(RigidBody))]
au-dessus de votre déclaration de classe (l'espace en dessous de tous vos usages).
Profitez et amusez-vous à créer des jeux!
Si nous considérons des scénarios courants où cette exception peut être levée, l'accès aux propriétés avec un objet en haut.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
ici, si l'adresse est nulle, vous obtiendrez NullReferenceException.
Donc, comme pratique, nous devons toujours utiliser la vérification nulle, avant d'accéder aux propriétés de ces objets (spécialement en générique)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Il s'agit essentiellement d'une exception de référence Null . Comme le déclare Microsoft-
Une exception NullReferenceException est levée lorsque vous essayez d'accéder à un membre d'un type dont la valeur est null.
Cela signifie que si un membre qui n'a aucune valeur et que nous faisons en sorte que ce membre effectue certaines tâches, le système lancera sans aucun doute un message et dira -
"Hé, attendez, ce membre n'a aucune valeur, il ne peut donc pas exécuter la tâche que vous lui remettez."
L'exception elle-même dit que quelque chose est référé mais dont la valeur n'est pas définie. Cela signifie donc que cela se produit uniquement lors de l'utilisation de types de référence, car les types de valeur ne sont pas nullables.
NullReferenceException ne se produira pas si nous utilisons des membres de type Value.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Le code ci-dessus montre une chaîne simple qui est affectée d'un null valeur .
Maintenant, lorsque j'essaie d'imprimer la longueur de la chaîne str , j'obtiens une exception non gérée de type «System.NullReferenceException» , car le membre str pointe vers null et il ne peut pas y avoir de longueur nulle.
' NullReferenceException ' se produit également lorsque nous oublions d'instancier un type de référence.
Supposons que j'ai une classe et une méthode membre. Je n'ai pas instancié ma classe, mais seulement nommé ma classe. Maintenant, si j'essaie d'utiliser la méthode, le compilateur générera une erreur ou émettra un avertissement (selon le compilateur).
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");
}
}
Le compilateur pour le code ci-dessus génère une erreur indiquant que la variable obj n'est pas affectée, ce qui signifie que notre variable a des valeurs nulles ou rien. Le compilateur pour le code ci-dessus génère une erreur indiquant que la variable obj n'est pas affectée, ce qui signifie que notre variable a des valeurs nulles ou rien.
NullReferenceException survient en raison de notre faute pour ne pas avoir vérifié la valeur de l'objet. Nous laissons souvent les valeurs des objets non contrôlées dans le développement du code.
Elle survient également lorsque nous oublions d'instancier nos objets. L'utilisation de méthodes, de propriétés, de collections, etc. qui peuvent renvoyer ou définir des valeurs nulles peut également être la cause de cette exception.
Il existe différentes façons et méthodes pour éviter cette exception renommée:
Vérification explicite: nous devons respecter la tradition de vérification des objets, propriétés, méthodes, tableaux et collections s'ils sont nuls. Cela peut être simplement implémenté en utilisant des instructions conditionnelles comme if-else if-else etc.
Gestion des exceptions: l'un des moyens importants de gérer cette exception. En utilisant de simples blocs try-catch-finally, nous pouvons contrôler cette exception et également en conserver un journal. Cela peut être très utile lorsque votre application est en phase de production.
Opérateurs nuls: L'opérateur nul coalescent et les opérateurs conditionnels nuls peuvent également être utilisés de manière pratique lors de la définition des valeurs des objets, des variables, des propriétés et des champs.
Débogueur: Pour les développeurs, nous avons la grande arme du débogage avec nous. Si nous rencontrons NullReferenceException pendant la phase de développement, nous pouvons utiliser le débogueur pour accéder à la source de l'exception.
Méthode intégrée: les méthodes système telles que GetValueOrDefault (), IsNullOrWhiteSpace () et IsNullorEmpty () vérifient les valeurs nulles et affectent la valeur par défaut s'il existe une valeur nulle.
Il y a déjà beaucoup de bonnes réponses ici. Vous pouvez également consulter une description plus détaillée avec des exemples sur mon blog .
J'espère que cela aide aussi!
Si l'on reçoit ce message lors de l'enregistrement ou de la compilation de la génération, fermez simplement tous les fichiers, puis ouvrez n'importe quel fichier à compiler et à enregistrer.
Pour moi, la raison était que j'avais renommé le fichier et que l'ancien fichier était toujours ouvert.