web-dev-qa-db-fra.com

Qu'est-ce qu'une exception NullReferenceException et comment y remédier?

J'ai du code et quand il s'exécute, il lance un NullReferenceException, en 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?

1876
John Saunders

Quelle est la cause?

Ligne de fond

Vous essayez d'utiliser quelque chose qui est null (ou Nothing dans VB.NET). Cela signifie que vous le définissez sur null ou que vous ne le définissez jamais.

Comme toute autre chose, null est transmis. S'il s'agit de null dans la méthode "A" , il est possible que la méthode "B" ait passé un null à . méthode "A".

null peut avoir différentes significations:

  1. Les variables d’objet non initialisées et donc ne pointent à rien. Dans ce cas, Si vous accédez aux propriétés ou aux méthodes de tels objets, cela provoque un NullReferenceException.
  2. Le développeur utilise avec null intentionnellement pour indiquer qu’aucune valeur significative n’est disponible. Notez que C # utilise le concept de types de données Nullable pour les variables (comme les tables de base de données peuvent avoir des champs nullables) - vous pouvez leur affecter null pour indiquer qu’elle ne contient aucune valeur, par exemple int? a = null; où le point d’interrogation indique qu’il est autorisé à stocker null dans la variable a. Vous pouvez vérifier cela avec if (a.HasValue) {...} ou avec if (a==null) {...}. Les variables nullables, comme a cet exemple, permettent d'accéder à la valeur via a.Value explicitement, ou tout aussi normalement via a.
    Remarque qui y accède via a.Value jette un InvalidOperationException au lieu d'un NullReferenceException si a est null - vous devez effectuer le contrôle à l'avance, c'est-à-dire que si vous avez une autre variable non nullable int b;, vous devez alors effectuer des affectations telles que if (a.HasValue) { b = a.Value; } ou plus courte if (a != null) { b = a; } .

La suite de cet article va plus en détail et montre les erreurs que beaucoup de programmeurs font souvent qui peuvent conduire à un NullReferenceException.

Plus précisement

Le moteur d'exécution lançant un NullReferenceException signifie toujours signifie la même chose: vous essayez d'utiliser une référence et la référence n'est pas initialisée (ou était initialisé , mais n'est plus initialisé ).

Cela signifie que la référence est null et que vous ne pouvez pas accéder à des membres (tels que des méthodes) via une référence null. Le cas le plus simple:

string foo = null;
foo.ToUpper();

Cela jettera un NullReferenceException à la deuxième ligne car vous ne pouvez pas appeler la méthode d'occurrence ToUpper() sur une référence string pointant vers null.

Débogage

Comment trouvez-vous la source d'un NullReferenceException? Les règles générales de débogage dans Visual Studio s'appliquent non seulement à l'exception proprement dite, qui sera renvoyée exactement à l'emplacement où elle se produit, mais également à: = placer (points d'arrêt stratégiques) et inspecter vos variables , soit en survolant leur nom avec la souris, en ouvrant une fenêtre (Quick) Watch ou en utilisant les différents panneaux de débogage tels que Locals et Autos.

Si vous souhaitez savoir où la référence est définie ou non, 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 coupure du débogueur sur un tel point d'arrêt, vous devez déterminer si vous vous attendez à ce que la référence soit non nulle, inspectez la variable et vérifiez qu'elle pointe vers une instance lorsque vous vous y attendez.

En suivant le flux de programme de cette manière, vous pouvez trouver l'emplacement où l'instance ne doit pas être null et la raison pour laquelle elle n'est pas correctement définie.

Exemples

Quelques scénarios courants où l'exception peut être levée:

Générique

ref1.ref2.ref3.member

Si ref1 ou ref2 ou ref3 est nul, alors vous aurez un NullReferenceException. Si vous voulez résoudre le problème, cherchez celui qui est nul en récrivant l'expression à son équivalent 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 null, ou la propriété User pourrait être null, ou la propriété Identity pourrait être null.

Indirect

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

Initialiseurs d'objets imbriqués

La même chose s'applique aux initialiseurs d'objet imbriqués:

Book b1 = new Book { Author = { Age = 45 } };

Cela se traduit par

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

Bien que le mot-clé new soit utilisé, il crée uniquement une nouvelle instance de Book, mais pas une nouvelle instance de Person, de sorte que la propriété Author est toujours null.

Initialiseurs de collection imbriqués

public class Person {
    public ICollection<Book> Books { get; set; }
}
public class Book {
    public string Title { get; set; }
}

Les initialiseurs de collection imbriqués se comportent 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" });

Le new Person crée uniquement une instance de Person, mais la collection Books est toujours null. La syntaxe d'initialisation de la collection ne crée pas de collection pour p1.Books, elle se traduit uniquement par les instructions p1.Books.Add(...).

Tableau

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

Éléments de tableau

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.

Tableaux déchiquetés

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.

Collection/Liste/Dictionnaire

Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
                               // There is no Dictionary to perform the lookup.

Plage Variable (Indirect/Différé)

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.

Événements

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

Conventions de nommage incorrectes:

Si vous avez nommé les champs différemment des locaux, vous avez peut-être compris que vous n'aviez jamais initialisé le champ.

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

Cela peut être résolu en suivant la convention voulant que les champs soient précédés d'un trait de soulignement:

private Customer _customer;

Cycle de vie d'une page 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!";
    }
}

Valeurs de session ASP.NET

// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();

Modèles de vue vides ASP.NET MVC

Si l'exception se produit lors du référencement d'une propriété de @Model dans une vue ASP.NET MVC, vous devez comprendre que la Model est définie dans votre méthode d'action lorsque vous return une vue. Lorsque vous renvoyez un modèle (ou une propriété de modèle) vide à 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 -->

Ordre de création de contrôle WPF et événements

Les contrôles WPF sont créés lors de l’appel de InitializeComponent dans l’ordre dans lequel ils apparaissent dans l’arbre visuel. Un NullReferenceException sera déclenché dans le cas de contrôles créés antérieurement avec des gestionnaires d'événements, etc., qui se déclenchent pendant InitializeComponent qui font référence à des 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 tente de faire référence à `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 code XAML (c’est-à-dire lister label1 avant comboBox1, ignorer les problèmes de conception, résoudrait au moins NullReferenceException ici.

Cast avec as

var myThing = someObject as Thing;

Cela ne déclenche pas une exception InvalidCastException mais renvoie un null lorsque la conversion échoue (et lorsque someObject est lui-même null). Alors soyez conscient de cela.

LINQ FirstOrDefault () et SingleOrDefault ()

Les versions simples First() et Single() lèvent des exceptions lorsqu'il n'y a rien. Les versions "OrDefault" renvoient null dans ce cas. Alors soyez conscient de cela.

pour chaque

foreach jette lorsque vous essayez d'itérer une collection null. Généralement causé par un résultat inattendu null à partir de méthodes renvoyant 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. Lance si les noeuds ne sont pas trouvés mais que le débogage initial montre que toutes les propriétés sont valides:

 foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

Façons d'éviter

Vérifier explicitement null et ignorer les valeurs nulles.

Si vous vous attendez à ce que la référence soit parfois nulle, vous pouvez vérifier qu'elle est bien null avant d'accéder aux membres de l'instance:

void PrintName(Person p) {
    if (p != null) {
        Console.WriteLine(p.Name);
    }
}

Vérifier explicitement null et fournir une valeur par défaut.

Les méthodes appel que vous comptez renvoyer une instance peuvent renvoyer 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;
}

Recherchez explicitement null à partir d'appels de méthode et lève une exception personnalisée.

Vous pouvez également lancer 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;
}

Utilisez Debug.Assert si une valeur ne doit jamais être null, pour résoudre le problème plus tôt que l'exception se produit.

Lorsque vous savez en cours de développement qu’une méthode peut peut-être, mais ne doit jamais renvoyer null, vous pouvez utiliser Debug.Assert() pour interrompre le processus dès que possible:

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 retrouvera pas dans la version de votre version , elle lancera à nouveau le NullReferenceException lorsque book == null à l'exécution en mode de publication.

Utilisez GetValueOrDefault() pour les types de valeur nullable afin de fournir une valeur par défaut lorsqu'ils 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

Utilisez l'opérateur de fusion nul: ?? [C #] ou If() [VB].

Le raccourci pour fournir une valeur par défaut lorsqu'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;
}

Utilisez l'opérateur de condition null: ?. ou ?[x] pour les tableaux (disponibles en C # 6 et VB.NET 14):

C'est aussi parfois appelé 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 null, le côté droit ne sera pas évalué et null sera renvoyé. Cela signifie des cas comme celui-ci:

var title = person.Title.ToUpper();

Si la personne n'a pas de titre, cela lève une exception car elle tente d'appeler ToUpper sur une propriété avec une valeur null.

En C # 5 et inférieur, cela peut être gardé avec:

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

Maintenant, la variable de titre sera null au lieu de lancer une exception. C # 6 introduit une syntaxe plus courte pour ceci:

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

La variable de titre sera donc null et l'appel à ToUpper ne sera pas effectué si person.Title est null.

Bien sûr, vous devez toujours vérifier la valeur null de title ou utiliser l'opérateur de condition null conjointement avec l'opérateur de fusion nul (??) 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 a la valeur null, l'expression renvoie la valeur 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 retournera le ith élément.

Utilisez le contexte null (disponible en C # 8):

Introduit en C # 8, les types de contexte null et référence nullable effectuent une analyse statique sur les variables et fournissent un avertissement au compilateur si une valeur peut être potentiellement nulle ou si elle a été définie sur null. Les types de référence nullable permettent explicitement d'autoriser les types à être null.

Le contexte d'annotation nullable et le contexte d'avertissement nullable peuvent être définis pour un projet à l'aide de l'élément Nullable de votre fichier csproj. Cet élément configure la manière dont le compilateur interprète la nullité des types et quels avertissements sont générés. Les paramètres valides sont:

  • enable: le contexte d'annotation Nullable est activé. Le contexte d'avertissement Nullable est activé. Les variables d'un type de référence, chaîne par exemple, ne sont pas nullables. Tous les avertissements d'invalidité sont activés.
  • disable: le contexte d'annotation Nullable est désactivé. Le contexte d'avertissement Nullable est désactivé. Les variables d'un type de référence sont inconscientes, tout comme les versions précédentes de C #. Tous les avertissements d'invalidité sont désactivés.
  • safeonly: le contexte d'annotation Nullable est activé. Le contexte d'avertissement nullable est safeonly. Les variables d'un type de référence ne sont pas nuls. Tous les avertissements d'invalidité de sécurité sont activés.
  • warnings: le contexte d'annotation Nullable est désactivé. Le contexte d'avertissement Nullable est activé. Les variables d'un type de référence sont inconscientes. Tous les avertissements d'invalidité sont activés.
  • safeonlywarnings: le contexte d'annotation nullable est désactivé. Le contexte d'avertissement nullable est safeonly. Les variables d'un type de référence sont inconscientes. Tous les avertissements d'invalidité de sécurité sont activés.

Un type de référence nullable est noté en utilisant la même syntaxe que les types de valeur nullable: un ? est ajouté au type de la variable.

Techniques spéciales pour le débogage et la fixation de derefs nuls dans les itérateurs

C # prend en charge les "blocs d'itérateur" (appelés "générateurs" dans d'autres langages populaires). Les exceptions de déréférencement nulles peuvent être particulièrement difficiles à déboguer dans les blocs d'itérateurs en raison d'une 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 whatever résulte en null, alors MakeFrob jette. 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 faux? Parce que le bloc itérateur ne s'exécute pas avant le foreach! L'appel à GetFrobs renvoie simplement un objet qui lorsqu'il sera itéré exécutera le bloc itérateur.

En écrivant une vérification NULL comme celle-ci, vous empêchez la déréférence NULL, mais vous déplacez l'exception d'argument NULL au point de l'itération , pas au point de l'appel , et c'est très déroutant à déboguer .

Le correct correctif 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();
}

En d’autres termes, créez une méthode d’aide privée dotée de la logique de bloc de l’itérateur et une méthode de surface publique effectuant la vérification nulle et renvoyant l’itérateur. Désormais, lorsque GetFrobs est appelée, la vérification de la valeur NULL est effectuée immédiatement, puis GetFrobsForReal est exécutée lorsque la séquence est itérée.

Si vous examinez la source de référence de LINQ to Objects, vous verrez que cette technique est utilisée dans l'ensemble. L'écriture est un peu plus lourde, mais cela facilite beaucoup le débogage des erreurs de nullité. Optimisez votre code pour le confort de l'appelant, pas pour le confort de l'auteur .

Une note sur les déréférences nulles dans un code non sécurisé

C # a un mode "non sécurisé" qui, comme son nom l’indique, est extrêmement dangereux, car les mécanismes de sécurité normaux assurant la sécurité de la mémoire et la sécurité du type ne sont pas appliqués. Vous ne devriez pas écrire de code non sécurisé à moins de bien comprendre le fonctionnement de la mémoire .

En mode non sécurisé, vous devez être conscient de deux faits importants:

  • le déréférencement d'un pointeur nul produit la même exception que le déréférencement d'une référence null
  • le déréférencement d'un pointeur non nul non valide peut produire cette exception dans certaines circonstances

Pour comprendre pourquoi, il est utile de comprendre comment .NET produit d’abord des exceptions de déréférencement nul. (Ces détails s'appliquent à .NET sous Windows; d'autres systèmes d'exploitation utilisent des mécanismes similaires.)

La mémoire est virtualisée sous Windows. chaque processus obtient un espace de mémoire virtuelle composé de nombreuses "pages" de mémoire suivies par le système d'exploitation. Chaque page de la mémoire comporte des indicateurs qui déterminent son utilisation: lecture, écriture, exécution, etc. La page la plus basse est marquée comme "produire une erreur si jamais utilisée de quelque manière que ce soit".

Un pointeur nul et une référence nulle en C # sont tous deux représentés en interne par le chiffre zéro; toute tentative de le déréférencer dans la mémoire correspondante provoque alors une erreur du système d'exploitation. Le runtime .NET détecte alors cette erreur et la transforme en exception de déréférence Null.

C'est pourquoi la déréférence d'un pointeur nul et d'une référence nulle produit la même exception.

Qu'en est-il du deuxième point? Le déréférencement de tout pointeur non valide qui se situe dans la page la plus basse de la mémoire virtuelle provoque la même erreur de système d'exploitation et, par conséquent, la même exception.

Pourquoi cela a-t-il un sens? Supposons que nous ayons une structure contenant deux ints et un pointeur non géré égal à null. Si nous essayons de déréférencer le second int de 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, il s’agit d’un déréférencement nul, car nous arrivons à cette adresse via le null.

Si vous travaillez avec du code non sécurisé et que vous obtenez une exception de déréférencement Null, sachez simplement que le pointeur incriminé n'a pas besoin d'être null. Il peut s'agir de n'importe quel emplacement de la page la plus basse et cette exception sera générée.

2304
John Saunders

Exception NullReference - Visual Basic

_NullReference Exception_ pour Visual Basic n'est pas différent de celui de C # . Après tout, ils signalent tous les deux la même exception définie dans le .NET Framework qu'ils utilisent tous les deux. Les causes uniques à 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 précédentes relatives au débordement de pile. Ceci afin de maximiser la pertinence en utilisant letypesdes situations souvent vues dans les posts. Un peu plus d'explications est également fourni pour ceux qui pourraient en avoir besoin. Un exemple similaire au vôtre estveryprobablement indiqué ici.

Note:

  1. Ceci est basé sur un concept: il n'y a pas de code à coller dans votre projet. Il est destiné à vous aider à comprendre les causes d'une NullReferenceException (NRE), comment le trouver, comment le réparer et comment l'éviter. Une NRE peut être provoquée de plusieurs façons, il est donc peu probable que ce soit votre seule rencontre.
  2. Les exemples (extraits de Stack Overflow) n'indiquent pas toujours le meilleur moyen de faire quelque chose en premier lieu.
  3. Généralement, le remède le plus simple est utilisé.

Signification de base

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 de ceux-ci:

  • Votre codedéclaréune variable d'objet, mais pasinitializeit (créer une instance ou 'instantiate' it)
  • Quelque chose que votre code supposait initialiser un objet ne l’a pas été.
  • Peut-être, un autre code invalide prématurément un objet encore en cours d'utilisation

Trouver la cause

Puisque le problème est une référence d'objet qui est Nothing, la réponse est de les examiner pour trouver laquelle. Puis déterminez 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.

IDE debug display

Vous devez également supprimer tous les blocs Try/Catch du code approprié, en particulier ceux où il n'y a rien dans le bloc Catch. Cela provoquera le blocage de votre code lorsqu'il essaiera d'utiliser un objet qui est Nothing. C’est ce que vous voulez car cela identifiera leemplacementexact du problème et vous permettra d’identifier l’objet qui l’a provoqué.

Un MsgBox dans la capture qui affiche _Error while..._ sera d'une aide minime. Cette méthode mène également aux questionsvery bad/ Stack Overflow, 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_ ( Debug -> Windows -> Locals ) pour examiner vos objets.

Une fois que vous savez quoi et où est le problème, il est généralement assez facile à résoudre et plus rapide que de poser une nouvelle question.

Voir également:

Exemples et remèdes

Objets de classe/Création d'une instance

_Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE
_

Le problème est que Dim ne crée pas de CashRegisterobject; il ne déclare qu'une variable nommée reg de ce type.Déclarerune variable d'objet et créer uninstancesont deux choses différentes.

Remède

L'opérateur New 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 est seulement approprié de créer l'instance plus tard:

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

Remarque: Ne pas utilisez à nouveau Dim 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 créera une variablelocal, reg, qui n'existe que dans ce contexte (sub). La variable reg de niveau module Scope que vous utiliserez partout ailleurs reste Nothing.

L'opérateur New est manquant. Il s'agit de la cause n ° 1 de _NullReference Exceptions_ dans les questions de débordement de pile examinées.

Visual Basic tente de clarifier le processus à plusieurs reprises à l'aide deNew: l'opérateurNewcrée un objet new et appelleSub New- le constructeur - où votre objet peut effectuer toute autre initialisation.

Pour être clair, Dim (ou Private) uniquementdéclareune variable et son Type. LeScopede la variable - qu'il existe pour l'ensemble du module/de la classe ou qu'il soit local à une procédure - est déterminé paril est déclaré. _Private | Friend | Public_ définit le niveau d'accès, pasScope.

Pour plus d'informations, voir:


Tableaux

Les tableaux doivent également être instanciés:

_Private arr as String()
_

Ce tableau a seulement été déclaré, pas créé. Il y a 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 de _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 assignées. Les déclarations de niveau 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 les objets Foo qu'il contient ne l’ont pas été.

Remède

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

En utilisant un List(Of T), il sera 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:


Listes et Collections

Les collections .NET (parmi lesquelles 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é que, 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 aboutira à un NRE, car barList est seulement déclaré, pas instancié. La création d'une instance de Foo ne créera pas également une instance de la variable interne barList. L'intention était peut-être de faire cela dans le constructeur:

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

Comme auparavant, cela 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) Class .


Objets du fournisseur de données

Travailler avec des bases de données offre de nombreuses opportunités pour une référence null car il peut y avoir plusieurs objets (Command, Connection, Transaction, Dataset, DataTable, DataRows....) utilisés simultanément. Remarque: Peu importe le fournisseur de données que vous utilisez - MySQL, SQL Server, OleDB, etc. - les concepts/sont identiques.

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 auparavant, l'objet ds Dataset a été déclaré, mais aucune instance n'a jamais été créée. DataAdapter remplira un DataSet existant, pas en créer un. Dans ce cas, puisque ds est une variable locale,le IDE vous avertit/que cela pourrait se produire:

img

Lorsqu'il est déclaré en tant que variable de niveau module/classe, comme cela semble être le cas avec con, le compilateur ne peut pas savoir si l'objet a été créé par une procédure en amont. Ne pas ignorer 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. DataTable nommé "Employé" n'a pas été créé. Résultat: NullReferenceException tente d'y accéder. Un autre problème potentiel est de supposer qu'il y aura Items qui pourrait ne pas l'être lorsque le SQL inclut une clause WHERE.

Remède

Puisque cela utilise une table, utiliser Tables(0) évitera les erreurs d’orthographe. Examiner _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 Rows affecté qui peut également être testé:

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

DataAdapter fournira TableNames comme indiqué dans l'exemple précédent, mais il n'analysera pas les noms de la table SQL ou de la base de données. En conséquence, ds.Tables("TICKET_RESERVATION") fait référence à une table inexistante.

Le Remède est le même, référencez la table par index:

_If ds.Tables(0).Rows.Count > 0 Then
_

Voir aussi DataTable Class .


Chemins d'objet/imbriqués

_If myFoo.Bar.Items IsNot Nothing Then
   ...
_

Le code teste uniquement Items alors que myFoo et Bar peuvent également être Nothing. Le remède consiste à tester l’ensemble de la chaîne ou du chemin des objets:

_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 que la première condition False est rencontrée. Cela permet au code de "percer" en toute sécurité dans le ou les objets, un "niveau" à la fois, en évaluant _myFoo.Bar_ uniquement après (et si) myFoo est considéré comme valide. Les chaînes ou chemins d’objets peuvent être 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 objet null. Ceci s'applique également aux contrôles:

_myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
_

Ici, myWebBrowser ou Document pourrait être Nothing ou l'élément _formfld1_ pourrait ne pas exister.


Contrôles d'UI

_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 peut ne pas avoir sélectionné quelque chose dans un ou plusieurs contrôles de l'interface utilisateur. _ListBox1.SelectedItem_ peut très bien être Nothing, donc _ListBox1.SelectedItem.ToString_ donnera un NRE.

Remède

Validez les données avant de les utiliser (utilisez également les paramètres _Option Strict_ 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
_

Sinon, vous pouvez utiliser _(ComboBox5.SelectedItem IsNot Nothing) AndAlso..._


Formulaires 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
_

C'est un moyen assez courant d'obtenir un NRE. En C #, selon le codage utilisé, IDE signalera que Controls n'existe pas dans le contexte actuel ou "ne peut pas faire référence à un membre non statique". Donc, dans une certaine mesure, cette situation est réservée à VB. Il est également complexe car il peut en résulter une défaillance en cascade.

Les tableaux et les collections ne peuvent pas être initialisés de cette façon. Ce code d'initialisation s'exécuteraavantle constructeur crée le Form ou le Controls. Par conséquent:

  • Les listes et la collection seront simplement vides
  • Le tableau contiendra cinq éléments de rien
  • L'affectation somevar donnera lieu à une NRE immédiate car rien ne possède une propriété _.Text_

Référencer des éléments de tableau ultérieurement aboutira à un NRE. Si vous faites cela dans _Form_Load_, en raison d'un bogue étrange, le IDEne peut pas/ signaler l'exception quand cela se produit. L'exception apparaîtralaterlorsque votre code tentera d'utiliser le tableau. Cette "exception silencieuse" est détaillée dans cet article . Pour nos besoins, la clé est que, lorsqu'une catastrophe survient lors de la création d'un événement de formulaire (_Sub New_ ou _Form Load_), des exceptions peuvent ne pas être signalées, le code quitte la procédure et affiche simplement le formulaire.

Puisqu'aucun autre code de votre événement _Sub New_ ou _Form Load_ ne s'exécutera après le NRE,de nombreuses autres chosespeuvent ê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
_

Remarque ceci s'applique à toutes les références de contrôle et de composant, rendant celles-ci illégales lorsqu'elles sont:

_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 fournisse pas d'avertissement, mais le remède consiste à déclarer les conteneurs au niveau du formulaire, mais initialize les dans le gestionnaire d'événements de chargement de formulaire lorsque les contrôles do existent. Cela peut être fait dans _Sub New_ tant que votre code est après l'appel InitializeComponent:

_' 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 de la matrice n'est peut-être pas encore sorti du bois. Aucun contrôle qui se trouve dans un contrôle conteneur (tel qu'un GroupBox ou Panel) ne sera trouvé dans _Me.Controls_; ils figureront dans la collection Controls de ce Panel ou de cette GroupBox. Un contrôle ne sera pas non plus retourné lorsque le nom du contrôle est mal orthographié (_"TeStBox2"_). Dans ce cas, Nothing sera à nouveau stocké dans ces éléments de tableau et un résultat NRE sera généré lorsque vous tenterez de le référencer.

Celles-ci devraient être faciles à trouver maintenant que vous savez ce que vous recherchez: VS shows you the error of your ways

"Button2" réside sur un Panel

Remède

Plutôt que des références indirectes par nom utilisant la collection Controls 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...})
_

Fonction ne retournant rien

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

Ceci est un cas où IDE vous avertira que 'tous les chemins ne renvoient pas de valeur et qu'un NullReferenceException peut en résulter'. Vous pouvez supprimer l'avertissement en remplaçant _Exit Function_ par _Return Nothing_, mais cela ne résout pas le problème. Tout ce qui essaie d'utiliser le retour quand _someCondition = False_ donnera un NRE:

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

Remède

Remplacez _Exit Function_ dans la fonction par _Return bList_. Renvoyer unemptyList n'est pas la même chose que renvoyer Nothing. S'il y a une chance qu'un objet retourné puisse être Nothing, testez-le avant de l'utiliser:

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

Essai/capture mal implémenté

Un Try/Catch mal implémenté peut cacher le problème et en créer 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
_

Ceci est un cas où un objet n'est pas créé comme prévu, mais démontre également l'utilité du compteur d'un Catch vide.

Il y a une virgule supplémentaire dans le code SQL (après 'mailaddress') qui génère une exception à _.ExecuteReader_. Une fois que Catch ne fait plus rien, Finally tente d'effectuer un nettoyage, mais comme vous ne pouvez pas Close un objet null DataReader, vous obtenez un résultat NullReferenceException tout neuf.

Un bloc vide Catch est le terrain de jeu du diable. Ce PO était déconcerté par le fait qu’il obtenait un NRE dans le bloc Finally. Dans d'autres situations, un Catch vide peut avoir pour résultat que quelque chose de beaucoup plus loin en aval se détraque et vous oblige à passer du temps à chercher les mauvaises choses au mauvais endroit pour résoudre le problème. ("L'exception silencieuse" décrite ci-dessus fournit la même valeur de divertissement.)

Remède

N'utilisez pas de blocs Try/Catch vides - laissez le code planter afin de pouvoir a) identifier la cause b) identifier l'emplacement et c) appliquer une solution appropriée. Les blocs Try/Catch ne sont pas destinés à masquer les exceptions à la personne spécialement qualifiée pour les résoudre - le développeur.


DBNull n'est pas la même chose que rien

_For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...
_

La fonction IsDBNull est utilisée pour tester si unvaleurest égal à _System.DBNull_: De MSDN:

La valeur System.DBNull indique que l'objet représente des données manquantes ou inexistantes. DBNull n'est pas la même chose que Nothing, ce qui indique qu'une variable n'a pas encore été initialisée.

Remède

_If row.Cells(0) IsNot Nothing Then ...
_

Comme auparavant, vous pouvez tester Nothing, puis pour 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...
_

Contrôles

_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 faire référence à une propriété entraînera une exception.

Remède

_If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
_

Le DataGridView

La DGV a quelques bizarreries 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 créera les colonnes, mais ne les nomme pas. Par conséquent, le code ci-dessus échoue lorsqu'il les référence par nom.

Remède

Nommez les colonnes manuellement ou référence par index:

_dgvBooks.Columns(0).Visible = True
_

Exemple 2 - Faites attention au 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
_

Lorsque votre DataGridView a AllowUserToAddRows comme True (valeur par défaut), le Cells dans la ligne vide/nouvelle en bas contiendra tous Nothing. La plupart des tentatives d'utilisation du contenu (par exemple, ToString) aboutissent à un NRE.

Remède

Utilisez une boucle _For/Each_ et testez la propriété IsNewRow pour déterminer s'il s'agit de la dernière ligne. Cela fonctionne que 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 boucle _For n_, modifiez le nombre de lignes ou utilisez _Exit For_ lorsque IsNewRow est vrai.


My.Settings (StringCollection)

Dans certaines circonstances, essayer d'utiliser un élément de _My.Settings_ qui est un StringCollection peut entraîner un 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. Ce sera le cas, mais seulement si vous avez déjà 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é, il 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 gestionnaire d'événements Load du formulaire, si 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 collection Settings ne devra être initialisée qu'à la première exécution de l'application. Une autre solution consiste à ajouter une valeur initiale à votre collection dans Projet -> Paramètres | FooBars , enregistrez le projet, puis supprimez la fausse valeur.


Points clés

Vous avez probablement oublié l'opérateur New.

ou

Quelque chose que vous avez supposé fonctionnerait parfaitement pour renvoyer un objet initialisé à votre code, ne l’a pas fait.

N'ignorez jamais les avertissements du compilateur et utilisez _Option Strict On_ (toujours).


Exception MSDN NullReference Exception

302

Un autre scénario consiste à convertir un objet null 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 plus complexes "à liaison tardive" où l'objet nul a été renvoyé à partir d'un code que vous ne possédez pas, et la conversion est par exemple générée 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, SelectedDate est en fait une propriété - de DateTime type - du type Calendar Web Control, et la liaison pourrait parfaitement renvoyer une valeur nulle. Le générateur ASP.NET implicite créera un morceau de code qui sera équivalent au code de distribution ci-dessus. Et cela soulèvera une NullReferenceException assez difficile à repérer, car elle réside dans un code généré par ASP.NET qui compile bien ...

224
Simon Mourier

Cela signifie que la variable en question n'est pointée vers rien. Je pourrais générer ceci comme suit:

SqlConnection connection = null;
connection.Open();

Cela jettera l’erreur car, bien que 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 l'erreur sera renvoyée.

Pour éviter cette erreur:

  1. Toujours initialiser vos objets avant d'essayer de faire quoi que ce soit avec eux.
  2. Si vous n'êtes pas sûr que l'objet est null, vérifiez-le avec object == null.

L'outil Resharper de JetBrains identifiera tous les emplacements de votre code susceptibles de contenir une erreur de référence nulle, ce qui vous permettra d'effectuer une vérification nulle. Cette erreur est la source numéro un de bugs, IMHO.

156
Chris B. Behrens

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 cette erreur, les objets pouvant être null doivent être testés 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
}
153
Jonathan Wood

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 est Nothing/null pour la variable de référence, cela signifie qu'elle ne contient pas de référence à une instance d'objet existant dans le segment de mémoire.

Vous avez soit jamais assigné quelque chose à la variable, jamais créé une instance de la valeur affectée à la variable, soit vous avez défini la variable égale à Nothing/null manuellement, soit vous avez appelé une fonction qui a défini la variable. to Nothing/null pour vous.

95
code master

Voici un exemple d’exception levée: lorsque vous essayez de vérifier quelque chose, la valeur 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 exception ArgumentNullException qui est généralement levée à titre de 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.

86
Alex KeySmith

Mise à jour de C # 8.0, 2019: types de référence nullables

C # 8.0 introduit types de référence nullable et types de référence non nullable. Donc, seuls les types de référence nullables doivent être vérifiés pour éviter une NullReferenceException.


Si vous n'avez pas initialisé de type de référence et que vous souhaitez définir ou lire l'une de ses propriétés, une exception NullReferenceException sera lancée.

Exemple:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Vous pouvez simplement éviter cela en vérifiant si la variable n'est pas null:

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 types de valeur et [types de référence] [3].

Donc, si vous avez affaire à types de valeur, des exceptions NullReferenceExceptions peuvent pas se produire. Bien que vous deviez rester vigilant lorsque vous traitez avec types de référence!

Comme son nom l'indique, seuls les types de référence 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 cochés):

  • dynamique
  • objet
  • chaîne

types de valeur (vous pouvez simplement ignorer ceux-ci):

  • Types numériques
  • Types intégraux
  • Types à virgule flottante
  • décimal
  • bool
  • Structures définies par l'utilisateur
85
Fabian Bigler

Un autre cas où NullReferenceExceptions peut se produire est l'utilisation (incorrecte) de l'opérateur as :

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; Car ne peut pas être converti/converti en Book. Lorsque cette conversion échoue, as renvoie null. Utiliser mybook après cela provoque un NullReferenceException.

En général, vous devez utiliser un transtypage ou as, comme suit:

Si vous vous attendez à ce que la conversion de type réussisse toujours (c.-à-d. Que vous savez ce que l'objet devrait être à l'avance), vous devez utiliser un transtypage:

ComicBook cb = (ComicBook)specificBook;

Si vous n'êtes pas sûr du type mais que vous voulez essayer de l'utiliser comme type spécifique, utilisez alors as:

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

Vous utilisez l'objet qui contient la référence de valeur null. Donc, cela donne une exception nulle. Dans l'exemple, la valeur de la chaîne est null et lors de la vérification de sa longueur, une 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: La référence à un objet n'est pas définie sur une instance d'un objet. à Program.Main ()

64
user1814380

Alors que quoi provoque une NullReferenceExceptions et les approches de éviter/corriger Une telle exception a été abordée dans d’autres réponses. Ce que beaucoup de programmeurs n’ont pas encore appris, c’est comment déborder de façon indépendante pendant le développement.

Dans Visual Studio, cela est généralement facile grâce au Visual Studio Debugger .


Tout d’abord, assurez-vous que l’erreur correcte sera interceptée - voir Comment puis-je autoriser la rupture sur 'System.NullReferenceException' dans VS2010? Remarque1

Puis soit Commencez par le débogage (F5) ou Attachez [le VS Debugger] pour exécuter le processus . À l'occasion, il peut être utile d'utiliser Debugger.Break , qui vous invitera à lancer le débogueur.

Désormais, lorsque l’exception NullReferenceException est levée (ou non gérée), le débogueur s’arrête (vous vous souvenez de la règle définie ci-dessus?) Sur la ligne sur laquelle l’exception s’est produite. Parfois, l'erreur sera facile à détecter.

Par exemple, dans la ligne suivante, le seul code que peut provoquer comme exception est si myString est évalué à null. Cela peut être vérifié en regardant le fenêtre de suivi ou en utilisant des expressions dans le fenêtre immédiate .

_var x = myString.Trim();
_

Dans des cas plus avancés, tels que les suivants, vous devrez utiliser l'une des techniques ci-dessus (fenêtres Watch ou Windows immédiates) pour inspecter les expressions afin de déterminer si _str1_ était null ou si _str2_ était null .

_var x = str1.Trim() + str2.Trim();
_

Une fois l'exception est que projection a été localisée, il est généralement facile de raisonner à l'envers pour savoir où la valeur null a été [incorrectement] introduite -

Prenez le temps nécessaire pour comprendre la cause de l'exception. Inspecter pour les expressions nulles. Inspectez les expressions précédentes qui auraient pu générer de telles expressions nulles. Ajoutez points d'arrêt et parcourez le programme comme il convient. Utilisez le débogueur.


1 Si Break on Throws est trop agressif et que le débogueur s'arrête sur un NPE de la bibliothèque .NET ou tierce, Break sur User-Unhandled peut être utilisé pour limiter les exceptions interceptées. De plus, VS2012 introduit 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) première chance qui sont émises en dehors de Mon Code et ne passent pas par Mon Code.

63
user2864740

Simon Mourier a donné cet exemple :

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

où une unboxing conversion (transt) à partir de object (ou d'une des classes System.ValueType ou System.Enum, ou d'un type d'interface) à un type de valeur (autre que Nullable<>) en lui-même donne la NullReferenceException.

Dans l’autre sens, une conversion à partir de un Nullable<> qui a HasValue égal à false à un type de référence, peut donner une référence null qui peut alors plus tard conduire à 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 sont dus aux règles spéciales utilisées par le moteur d'exécution lors de la mise en boîte des instances Nullable<>.

57
Jeppe Stig Nielsen

Ajout d'un cas où le nom de classe pour l'entité utilisée dans la structure 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 avez un nom d'entité Contact.

Ensuite, le code suivant lève 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é contact. Parfois, les classes d'entités sont des classes partielles afin que vous puissiez les étendre également 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és étendra System.Web.UI.Page, cette erreur se produit.

Pour la discussion, jetez un oeil à NullReferenceException in DbContext.saveChanges ()

41
AbhinavRanjan

Un autre cas général dans lequel cette exception pourrait être commise consiste à se moquer de classes pendant les tests unitaires. Quel que soit le cadre utilisé, vous devez vous assurer que tous les niveaux appropriés de la hiérarchie de classes sont correctement moqués. En particulier, toutes les propriétés de HttpContext qui sont référencées par le code testé doivent être simulées.

Voir " Exception de NullReferenceException levée lors du test de AuthorizationAttribute personnalisé " pour un exemple quelque peu détaillé.

40
John Saunders

J'ai une perspective différente pour répondre à cela. Ce type de réponses "Que puis-je faire pour l'éviter?"

Lorsqu'il travaille 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, Dependency Injection Container peut être utilisé pour initialiser les services afin d'éviter le NullReferenceException. Cela signifie donc que vous n'avez pas à vous soucier de la vérification de null et à simplement appeler les services du contrôleur comme s'ils étaient 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();
    }
}
39
Mukus

A propos de "que dois-je faire à ce sujet" , il peut y avoir beaucoup de réponses.

Un moyen plus "formel" d’empêcher de telles conditions d’erreur lors du développement est d’appliquer conception par contrat dans votre code. Cela signifie que vous devez définir des invariants de classe , et/ou même une fonction/méthode , des préconditions et sur votre système, tout en se développant.

En bref, les invariants de classe garantissent que certaines contraintes de votre classe ne seront pas violées en utilisation normale (et que, par conséquent, la classe ne sera pas ). entrer dans un état incohérent). Les conditions préalables signifient que les données saisies en entrée d'une fonction/méthode doivent respecter certaines contraintes et que ne doit jamais être violé et postconditions signifient qu'une sortie de fonction/méthode doit à nouveau respecter les contraintes définies sans jamais les violer. Les conditions du contrat doivent ne jamais être violées lors de l'exécution d'un programme exempt de bogues. Par conséquent, la conception par contrat est vérifiée en pratique en mode débogage, tout en étant désactivé dans les versions pour optimiser les performances du système développé.

De cette façon, vous pouvez éviter NullReferenceException les cas résultant d'une violation du jeu de contraintes. Par exemple, si vous utilisez une propriété d'objet X dans une classe et tentez ultérieurement d'appeler l'une de ses méthodes et que X a une valeur null, cela aboutira à 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 une valeur nulle" comme condition préalable à la méthode, vous pouvez alors 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 Contrats de code existe pour les applications .NET.

Vous pouvez également appliquer la conception par contrat en utilisant assertions.

UPDATE: Il convient de mentionner que ce terme a été inventé par Bertrand Meyer en rapport avec sa conception du langage de programmation Eiffel .

37
Nick Louloudakis

Une NullReferenceException est renvoyée lorsque nous essayons d'accéder aux propriétés d'un objet null ou lorsqu'une valeur de chaîne devient vide et que nous essayons d'accéder à des méthodes de chaîne.

Par exemple:

  1. Quand une méthode de chaîne d'une chaîne vide accédée:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
    
  2. Lorsqu'une propriété d'un objet null a accédé:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 
    
35
Hemant Bavle

TL; DR: Essayez d’utiliser Html.Partial au lieu de Renderpage


J'obtenais Object reference not set to an instance of an object lorsque 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 en:

@{
    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 pour commencer était parce que Visual Studio parfois jette des lignes sinueuses ressemblant à une erreur sous Html.Partial si c'est à l'intérieur d'une boucle foreach construite différemment, 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 aucun problème avec cette "erreur". J'ai pu éliminer l'erreur en modifiant la structure de la boucle foreach pour qu'elle ressemble à ceci:

@foreach(var M in MyEntities){
    ...
}

Bien que j’ai le sentiment que c’est parce que Visual Studio a mal interprété les esperluettes et les crochets.

30
Travis Heeter

Que pouvez-vous faire à ce sujet?

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 pour prévenir le problème ou au moins 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 lancer un ArgumentNullException, une exception évidemment créée à cet effet précis.

Le constructeur de la variable ArgumentNullException prend même le nom du paramètre et un message sous forme d'arguments afin que vous puissiez indiquer exactement au développeur le problème.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Utiliser les outils

Il existe également plusieurs bibliothèques qui peuvent aider. "Resharper", par exemple, peut vous envoyer des avertissements lorsque vous écrivez du code, surtout si vous utilisez leur attribut: NotNullAttribute

Il existe des "contrats de code Microsoft" dans lesquels vous utilisez une syntaxe telle que Contract.Requires(obj != null) qui vous permet de vérifier l'exécution et la compilation: Présentation des contrats de code .

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, obj sera vérifié pour une valeur nulle lors de l'exécution. Voir: vérification null PostSharp

Solution de code simple

Ou vous pouvez toujours coder votre propre approche en utilisant du vieux code simple. Par exemple, voici une structure que vous pouvez utiliser pour intercepter des références null. Il est calqué sur le 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 de la même manière que vous utiliseriez Nullable<T> sauf que vous vouliez accomplir exactement le contraire - ne pas autoriser 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 converti vers et depuis T afin que vous puissiez l'utiliser pratiquement n'importe où vous en avez besoin. Par exemple, vous pouvez transmettre un objet Person à une méthode prenant un 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 avec nullable, vous accéderiez à la valeur sous-jacente via la propriété Value. Vous pouvez également utiliser une conversion 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 retourne simplement T (dans ce cas Person) en effectuant un transtypage. 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" };
}

Combinaison avec extension

Combinez NotNull<T> avec une méthode d'extension pour couvrir encore plus de situations. Voici un exemple de ce à quoi la méthode d'extension peut ressembler:

[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 d'utilisation:

var person = GetPerson().NotNull();

GitHub

Pour votre référence, le code ci-dessus est disponible sur GitHub. Vous pouvez le trouver sur:

https://github.com/luisperezphd/NotNull

Fonction de langage associé

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'entre eux est null l'expression entière renvoie null.

Cela réduit le nombre de vérifications nulles que vous devez faire dans certains cas. La syntaxe est de mettre un point d'interrogation avant chaque point. Prenez le code suivant par exemple:

var address = country?.State?.County?.City;

Imaginez que country soit un objet de type Country ayant une propriété appelée State et ainsi de suite. Si country, State, County ou City est null, alors address will benull. Therefore you only have to check whetheraddressisnull`.

C'est une fonctionnalité intéressante, mais qui vous donne moins d'informations. Cela ne permet pas de déterminer lequel des 4 est nul.

Intégré comme Nullable?

C # a un raccourci agréable pour Nullable<T>, vous pouvez faire quelque chose de nullable en mettant un point d’interrogation après le type, de la même manière que int?.

Ce serait bien si C # avait quelque chose comme la structure NotNull<T> 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).

22
Luis Perez

Vous pouvez corriger l'erreur NullReferenceException de manière claire à l'aide d'opérateurs Null-conditionnels de c # 6 et écrire moins de code pour gérer les contrôles NULL.

Il est utilisé pour tester null avant d'effectuer une opération d'accès membre (?.) 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 null lorsque p est null ou lorsque p.Spouse est null.

Sinon, le nom de la variable se verra attribuer la valeur de p.Spouse.FirstName.

Pour plus de détails: opérateurs nuls-conditionnels

9
M.Hassan

La ligne d'erreur "Référence d'objet non définie sur une instance d'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 correctifs/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 lève une erreur car la référence de la classe myClass est déclarée mais non instanciée ou une instance d'objet n'est pas affectée au référent de cette classe.

Pour résoudre ce problème, vous devez instancier (attribuer un objet à une référence de cette classe).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
8
Jaimin Dave

Fait intéressant, aucune des réponses sur cette page ne mentionne les deux cas Edge, espérons que cela ne dérange personne si je les ajoute:

Cas Edge n ° 1: accès simultané à un dictionnaire

Les dictionnaires génériques dans .NET ne sont pas thread-safe et ils parfois peuvent lancer un NullReference ou même (plus fréquemment) un KeyNotFoundException lorsque vous essayez d'accéder à une clé à partir de deux concurrents les discussions. L'exception est assez trompeuse dans ce cas.

Edge case # 2: code dangereux

Si une variable NullReferenceException est renvoyée par le code unsafe, vous pouvez examiner vos variables de pointeur et les vérifier pour IntPtr.Zero ou quelque chose du genre. Ce qui est la même chose ("exception de pointeur nul"), mais dans le code peu sûr, les variables sont souvent transtypées en types de valeur/tableaux, etc., et vous cognez votre tête contre le mur, en vous demandant comment un type de valeur peut jeter cela exception.

(Une autre raison de ne pas utiliser de code non sécurisé sauf si vous en avez besoin, soit dit en passant)

8
jazzcat

NullReferenceException ou Une référence d'objet non définie à une instance d'un objet se produit lorsqu'un objet de la classe que vous tentez 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érons 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 indiqué 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 renvoie l'exception NullReferenceException.

3
Nick

Eh bien, en termes simples:

Vous essayez d'accéder à un objet qui n'est pas créé ou actuellement en mémoire.

Alors, comment aborder ceci:

  1. Déboguer et laisser le débogueur se rompre ... Cela vous amènera directement à la variable qui est cassée ... Maintenant, votre tâche consiste simplement à résoudre ce problème .. Utiliser le new mot-clé à l'endroit approprié.

  2. Si cela est causé par certaines commandes database parce que l'objet n'est pas présent, il vous suffit de faire une vérification nulle et de le gérer:

    if (i == null) {
        // Handle this
    }
    
  3. Le plus difficile .. si le GC a déjà collecté l'objet ... Ceci se produit généralement si vous essayez de trouver un objet à l'aide de chaînes ... C'est-à-dire le trouver par son nom, il se peut que le GC l'ait déjà nettoyé ... C'est difficile à trouver et cela posera tout un problème ... Une meilleure solution pour y remédier, faites des contrôles nuls chaque fois que nécessaire pendant le processus de développement. Cela vous fera gagner beaucoup de temps.

En cherchant par nom, je veux dire par quelque structure que vous pouvez utiliser FIndObjects en utilisant des chaînes et le code pourrait ressembler à ceci: FindObject ("ObjectName");

2
Akash Gutha

Littéralement, le moyen le plus simple de réparer une NullReferenceExeption comporte deux manières. Si vous avez par exemple un objet GameObject avec un script et une variable nommée rb (rigidbody), cette variable commencera à zéro lorsque vous démarrez votre partie.
C'est pourquoi vous obtenez une NullReferenceExeption car l'ordinateur ne dispose pas de donné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:

  1. Ajoutez un RigidBody à votre objet avec AddComponent> Physics> Rigidbody
    Puis entrez dans votre script et tapez rb = GetComponent<Rigidbody>();
    Cette ligne de code fonctionne mieux sous vos fonctions Start() ou Awake().
  2. Vous pouvez ajouter un composant par programme et affecter la variable en même temps avec une ligne de code: rb = AddComponent<RigidBody>();

Notes complémentaires: Si vous souhaitez que Unit ajoute un composant à votre objet et que vous en ayez oublié un, vous pouvez taper [RequireComponent(typeof(RigidBody))] au-dessus de votre déclaration de classe (l'espace situé au-dessous de toutes vos utilisations).
Profitez et amusez-vous à faire des jeux!

0
CausticLasagne

Si nous considérons des scénarios courants dans lesquels cette exception peut être levée, accéder 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 adresse est null, vous obtiendrez NullReferenceException.

Donc, comme pratique, nous devrions toujours utiliser le contrôle nul avant d’accéder aux propriétés de tels 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
0
Hiran