1871 votes

Qu'est-ce qu'une NullReferenceException, et comment la réparer ?

J'ai du code et quand il s'exécute, il jette une NullReferenceException en disant :

La référence de l'objet ne correspond pas à une instance d'un objet.

Qu'est-ce que cela signifie, et que puis-je faire pour corriger cette erreur ?

0 votes

L'assistant d'exception de VS 2017 sera plus utile pour diagnostiquer la cause de cette exception blogs.msdn.microsoft.com/visualstudio/2016/11/28/ sous Nouvel assistant d'exception .

0 votes

Chers futurs visiteurs, les réponses à cette question s'appliquent également à une ArgumentNullException . Si votre question a été fermée car elle fait double emploi avec celle-ci, et que vous rencontrez un problème d'ENA, veuillez suivre les instructions dans les réponses pour déboguer et résoudre votre problème.

0 votes

@will ANE ne devrait se produire que si un null est passé comme paramètre. Pouvez-vous donner un exemple d'une question ANE fermée en tant que doublon de cette question ?

2668voto

John Saunders Points 118808

Quelle en est la cause ?

Ligne de fond

Vous essayez d'utiliser quelque chose qui est null (ou Nothing en VB.NET). Cela signifie que vous pouvez soit le définir sur null ou vous ne l'avez jamais réglé sur quoi que ce soit.

Comme tout le reste, null circule. Si c'est null sur la méthode "A", il se pourrait que la méthode "B" ait passé une null à méthode "A".

null peuvent avoir des significations différentes :

  1. Les variables d'objet qui sont non initialisé et donc ne mènent à rien. Dans ce cas, si vous accédez à des membres de tels objets, cela provoque une NullReferenceException .
  2. Le développeur est en utilisant null intentionnellement pour indiquer qu'il n'y a pas de valeur significative 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 assigner null pour indiquer qu'il n'y a pas de valeur stockée, par exemple int? a = null; (qui est un raccourci pour Nullable<int> a = null; ) où le point d'interrogation indique qu'il est autorisé à enregistrer null en variable a . Vous pouvez le vérifier soit avec if (a.HasValue) {...} ou avec if (a==null) {...} . Les variables annulables, comme a dans cet exemple, permettre d'accéder à la valeur via a.Value de manière explicite, ou simplement de manière normale via a .
    Note que le fait d'y accéder via a.Value lance un InvalidOperationException au lieu d'un NullReferenceException si a es null - vous devez effectuer la vérification au préalable, c'est-à-dire que si vous avez une autre variable non nullisable int b; alors vous devriez faire des missions comme if (a.HasValue) { b = a.Value; } ou plus court if (a != null) { b = a; } .

La suite de cet article entre dans le détail et montre les erreurs que de nombreux programmeurs commettent souvent et qui peuvent conduire à un échec. NullReferenceException .

Plus précisément

El runtime en lançant 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ée (ou elle l'a été). une fois initialisé, mais est plus du tout initialisé).

Cela signifie que la référence est null et vous ne pouvez pas accéder aux membres (tels que les méthodes) par l'intermédiaire d'un fichier de type null référence. Le cas le plus simple :

string foo = null;
foo.ToUpper();

Ceci lancera un NullReferenceException à la deuxième ligne parce que vous ne pouvez pas appeler la méthode d'instance ToUpper() sur un string référence pointant vers null .

Débogage

Comment trouver la source d'un NullReferenceException ? En dehors de l'examen de 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 contrôlez vos variables soit en passant la souris sur leur nom, en ouvrant une fenêtre (Quick)Watch ou en utilisant les différents panneaux de débogage comme Locals et Autos.

Si vous voulez savoir où la référence est ou n'est pas définie, faites un clic droit sur son nom et sélectionnez "Find All References". Vous pouvez alors 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 la référence doit être non nulle, inspecter la variable et vérifier qu'elle pointe vers une instance au moment où vous le souhaitez.

En suivant le déroulement du programme de cette manière, vous pouvez trouver l'endroit où l'instance ne devrait pas être nulle, et pourquoi 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 obtiendrez un NullReferenceException . Si vous voulez résoudre le problème, trouvez lequel est nul en réécrivant l'expression en 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 El HttpContext.Current pourrait être nul, ou le User pourrait être nulle, ou la propriété Identity pourrait être nulle.

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 voulez éviter la référence nulle de l'enfant (Personne), vous pouvez l'initialiser dans le constructeur de l'objet parent (Livre).

Initialiseurs d'objets imbriqués

Il en va de même pour les initialisateurs d'objets imbriqués :

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

Cela se traduit par :

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

Alors que le new est utilisé, il crée seulement une nouvelle instance de Book mais pas une nouvelle instance de Person donc le Author la propriété est toujours null .

Initialisateurs de collections imbriquées

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

La collection imbriquée Initializers 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" });

El new Person crée uniquement une instance de Person mais le Books La collection est toujours null . La collection Initializer La syntaxe ne crée pas de collection pour p1.Books il se traduit uniquement par le p1.Books.Add(...) déclarations.

Array

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

Éléments du 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.

Matrices en dents de scie

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 (indirecte/différée)

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 (C#)

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

(Remarque : le compilateur VB.NET insère des contrôles de nullité pour l'utilisation des événements, il n'est donc pas nécessaire de vérifier les événements pour les éléments suivants Nothing en VB.NET).

Mauvaises conventions d'appellation :

Si vous avez nommé les champs différemment des locaux, vous vous êtes peut-être rendu compte que vous n'avez 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);
    }
}

Ce problème peut être résolu en suivant la convention qui consiste à préfixer les champs par un trait de soulignement :

    private Customer _customer;

Cycle de vie des pages 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();

ASP.NET MVC modèles de vues vides

Si l'exception se produit lors de la référence à une propriété de @Model dans un ASP.NET MVC View vous devez comprendre que le Model est défini 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 depuis 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 des contrôles WPF et événements

WPF sont créés lors de l'appel à InitializeComponent dans l'ordre où ils apparaissent dans l'arbre visuel. A NullReferenceException sera soulevée dans le cas de contrôles créés au début de l'opération, avec des gestionnaires d'événements, etc. 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 référencer `label1, il n'aura pas encore été créé.

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReferenceException here!!
}

Changer l'ordre des déclarations dans le XAML (c'est-à-dire l'inscription label1 avant comboBox1 (en ignorant les questions de philosophie de la conception) permettrait au moins de résoudre le problème de l'utilisation de l'énergie. NullReferenceException ici.

Cast avec as

var myThing = someObject as Thing;

Cela ne lance pas un InvalidCastException mais renvoie un null lorsque le casting échoue (et lorsque someObject est lui-même nul). Il faut donc en être conscient.

LINQ FirstOrDefault() y SingleOrDefault()

Les versions simples First() y Single() lancer des exceptions lorsqu'il n'y a rien. Les versions "OrDefault" retournent null dans ce cas. Il faut donc en être conscient.

foreach

foreach se lance lorsque vous essayez d'itérer sur un fichier null collection. Généralement causée par une null le résultat des méthodes qui renvoient des collections.

List<int> list = null;    
foreach(var v in list) { } // NullReferenceException here

Exemple plus réaliste - sélectionner des nœuds dans un document XML. Lance une requête si les nœuds ne sont pas trouvés, mais le débogage initial montre que toutes les propriétés sont valides :

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

Les moyens d'éviter

Vérifier explicitement que null et ignorer null valeurs.

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

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

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

Les méthodes que vous appelez en attendant une instance peuvent retourner 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;
}

Vérifier explicitement que null à partir d'appels de méthodes et de lancer une exception personnalisée.

Vous pouvez également lancer une exception personnalisée, pour ensuite l'attraper dans le code d'appel :

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 afin de détecter le problème avant que l'exception ne se produise.

Lorsque vous savez pendant le développement qu'une méthode pourrait, mais ne devrait jamais retourner null vous pouvez utiliser Debug.Assert() à rompre le plus rapidement possible lorsqu'il 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 ce contrôle ne se retrouvera pas dans votre build de version ce qui entraîne l'envoi du message NullReferenceException à nouveau lorsque book == null au moment de l'exécution en mode release.

Utilisez GetValueOrDefault() para 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 coalescence nul : ?? [C#] ou If() [VB].

Le raccourci pour fournir une valeur par défaut lorsqu'un null est rencontrée :

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 nulle : ?. o ?[x] pour les tableaux (disponible en C# 6 et VB.NET 14) :

On l'appelle aussi parfois l'opérateur de navigation sûre ou Elvis (d'après sa forme). Si l'expression du côté gauche de l'opérateur est nulle, alors le côté droit ne sera pas évalué, et null sera retourné à la place. Cela signifie des cas comme celui-ci :

var title = person.Title.ToUpper();

Si la personne n'a pas de titre, une exception sera levée parce que l'on essaie de faire appel à la fonction ToUpper sur une propriété dont la valeur est nulle.

En C# 5 et en dessous, on peut s'en prémunir :

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

Désormais, la variable title sera nulle au lieu de déclencher une exception. C# 6 introduit une syntaxe plus courte pour cela :

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

Ainsi, la variable titre sera null et l'appel à ToUpper n'est pas faite si person.Title es null .

Bien sûr, vous toujours doivent vérifier title para null ou utiliser l'opérateur de condition nulle avec l'opérateur de coalescence nulle ( ?? ) 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");

Cette opération aura les effets suivants : Si myIntArray es 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 les i th élément.

Utiliser le contexte nul (disponible en C# 8) :

Introduit en C# 8 les contextes nuls et les types de référence nuls effectuent une analyse statique des variables et fournissent un avertissement au compilateur si une valeur peut être potentiellement null ou ont été réglés sur null . Les types de référence nullables 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 la commande Nullable 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 les suivants :

  • enable : Le contexte d'annotation nullable est activé. Le contexte d'avertissement nullable est activé. Les variables de type référence, chaîne de caractères, par exemple, ne sont pas annulables. Tous les avertissements de nullité sont activés.
  • disable : Le contexte d'annotation nullable est désactivé. Le contexte d'avertissement nullable est désactivé. Les variables de type référence sont oblivables, comme dans les versions précédentes de C#. Tous les avertissements de nullité sont désactivés.
  • safeonly : Le contexte d'annotation nullable est activé. Le contexte d'annotation nullable est safeonly. Les variables d'un type référence sont non-nullables. Tous les avertissements de nullité de sécurité sont activés.
  • warnings : Le contexte d'annotation nullable est désactivé. Le contexte d'annotation nullable est activé. Les variables de type référence sont oblivables. Tous les avertissements de nullité sont activés.
  • safeonlywarnings : Le contexte d'annotation nullable est désactivé. Le contexte d'annotation nullable est safeonly. Les variables de type référence sont oblitérées. Tous les avertissements de nullité de sécurité sont activés.

Un type de référence annulable est noté à l'aide de la même syntaxe que les types de valeur annulables : un ? est ajouté au type de la variable.

Techniques spéciales pour déboguer et corriger les derefs nuls dans les itérateurs

C# supporte les "blocs d'itérateurs" (appelés "générateurs" dans d'autres langages populaires). NullReferenceException peut être particulièrement délicat à déboguer dans les blocs d'itérateurs 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 whatever résulte en null puis MakeFrob va lancer. 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 n'a pas réellement exécuter jusqu'à ce que le foreach ! L'appel à GetFrobs renvoie simplement un objet qui en cas d'itération exécutera le bloc itérateur.

En rédigeant un null En vérifiant ainsi, vous évitez que le NullReferenceException mais vous déplacez le NullArgumentException jusqu'à la pointe de la itération mais pas au point de appelez et c'est très difficile à déboguer .

La bonne solution 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, il faut créer une méthode d'aide privée qui contient la logique du bloc d'itérateurs et une méthode de surface publique qui effectue le bloc d'itérateurs. null et renvoie l'itérateur. Maintenant, lorsque GetFrobs est appelé, le null se produit immédiatement, et ensuite GetFrobsForReal s'exécute lorsque la séquence est itérée.

Si vous examinez la source de référence pour LINQ à Objets, vous verrez que cette technique est utilisée partout. Elle est légèrement plus compliquée à écrire, mais elle facilite le débogage des erreurs de nullité. Optimisez votre code pour la commodité de l'appelant, pas pour celle de l'auteur. .

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

C# possède un mode "non sécurisé" qui, comme son nom l'indique, est extrêmement dangereux car les mécanismes de sécurité normaux qui assurent la sécurité de la mémoire et des types ne sont pas appliqués. Vous ne devriez pas écrire de code non sécurisé sans avoir une connaissance approfondie du fonctionnement de la mémoire. .

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

  • déréférencement d'une valeur nulle pointeur produit la même exception que le déréférencement d'une valeur nulle. référence
  • déréférencement d'un pointeur non nul invalide puede produire cette exception dans certaines circonstances

Pour comprendre pourquoi il en est ainsi, il faut comprendre comment .NET produit NullReferenceException en premier lieu. (Ces détails s'appliquent à .NET fonctionnant sous Windows ; d'autres systèmes d'exploitation utilisent des mécanismes similaires).

La mémoire est virtualisée dans Windows chaque processus dispose d'un espace mémoire virtuel composé de nombreuses "pages" de mémoire qui sont suivies par le système d'exploitation. Chaque page de mémoire possède des drapeaux qui déterminent comment elle peut être utilisée : lecture, écriture, exécution, etc. Le site le plus bas La page est marquée comme "produisant une erreur si jamais elle est utilisée de quelque manière que ce soit".

Tant un pointeur nul qu'une référence nulle en C# sont représentés en interne comme le nombre zéro, et donc toute tentative de déréférencement dans sa mémoire correspondante provoque une erreur du système d'exploitation. Le moteur d'exécution .NET détecte alors cette erreur et la transforme en un message d'erreur. NullReferenceException .

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

Qu'en est-il du deuxième point ? Déréférencement tout Un pointeur invalide 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 cela a-t-il un sens ? Supposons que nous ayons une structure contenant deux int, et un pointeur non géré égal à null. Si nous essayons de déréférencer le deuxième int dans la structure, la fonction CLR ne tentera pas d'accéder à la mémoire située à l'emplacement zéro ; il accédera à la mémoire située à l'emplacement quatre. Mais logiquement, il s'agit d'une déréférence nulle car nous accédons à cette adresse via la nullité.

Si vous travaillez avec du code non sécurisé et que vous obtenez une NullReferenceException Si vous avez besoin d'aide, sachez que le pointeur en question ne doit pas nécessairement être nul. Il peut être à n'importe quel endroit de la page la plus basse, et cette exception sera produite.

64 votes

C'est peut-être une remarque stupide mais la première et meilleure façon d'éviter ce problème ne serait-elle pas d'initialiser l'objet ? Pour moi, si cette erreur se produit, c'est généralement parce que j'ai oublié d'initialiser quelque chose comme l'élément du tableau. Je pense qu'il est beaucoup moins courant de définir l'objet comme nul et de le référencer ensuite. Peut-être donner la façon de résoudre chaque problème à côté de la description. C'est toujours un bon article.

34 votes

Et s'il n'y a pas d'objet, mais plutôt la valeur de retour d'une méthode ou d'une propriété ?

8 votes

L'exemple du livre et de l'auteur est un peu bizarre. .... Comment cela peut-il se compiler ? Comment intellisense fonctionne-t-il ? Qu'est-ce que c'est ? Je ne suis pas doué pour l'informa...

231voto

Simon Mourier Points 49585

Un autre scénario est celui où l'on fait passer un objet nul dans un objet type de valeur . Par exemple, le code ci-dessous :

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

Il lancera un NullReferenceException sur la distribution. Cela semble assez évident dans l'exemple ci-dessus, mais cela peut se produire dans des scénarios plus complexes de "liaison tardive" où l'objet nul a été renvoyé par un code dont vous n'êtes pas le propriétaire, et où le cast 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 Calendrier :

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

Ici, SelectedDate est en fait une propriété - de DateTime type - de la Calendar Web Control, et la liaison pourrait parfaitement retourner quelque chose de nul. Le générateur ASP.NET implicite va créer un morceau de code qui sera équivalent au code coulé ci-dessus. Et cela va générer un NullReferenceException qui est assez difficile à repérer, car il se trouve dans le code généré par ASP.NET qui compile bien...

7 votes

Belle prise. Une façon de l'éviter : DateTime x = (DateTime) o as DateTime? ?? defaultValue;

172voto

Jonathan Wood Points 26443

Cela signifie que votre code a utilisé une variable de référence d'objet qui était définie comme nulle (c'est-à-dire qu'elle ne faisait pas référence à une instance d'objet réelle).

Pour éviter cette erreur, les objets qui pourraient être nuls 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
}

169voto

Chris B. Behrens Points 4407

Cela signifie que la variable en question ne pointe vers rien. Je pourrais générer ceci comme suit :

SqlConnection connection = null;
connection.Open();

Cela entraînera une erreur car, bien que j'aie déclaré la variable " connection "mais il ne pointe vers rien. Lorsque j'essaie d'appeler le membre " Open "Il n'y a pas de référence à résoudre, et l'erreur sera levée.

Pour éviter cette erreur :

  1. Initialisez toujours 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 nul, vérifiez-le avec object == null .

JetBrains ReSharper identifiera tous les endroits de votre code où une erreur de référence nulle est possible, ce qui vous permettra de mettre en place une vérification des références nulles. Cette erreur est la première source de bogues, à mon avis.

3 votes

L'outil Resharper de JetBrains identifiera chaque endroit de votre code qui présente la possibilité d'une erreur de référence nulle. C'est incorrect. J'ai une solution sans cette détection, pourtant le code aboutit occasionnellement à l'exception. Je soupçonne que c'est parfois indétectable - par eux au moins - lorsque le multithreading est impliqué, mais je ne peux pas commenter davantage car je n'ai pas encore identifié l'emplacement de mon bug.

1 votes

Mais comment le résoudre lorsque l'exception NullReferenceException survient en utilisant HttpContext.Current.Responce.Clear(). Il n'est pas résolu par l'une des solutions ci-dessus. parce que tout en créant son objet de HttpContext alors une erreur vient "Overload resolution failed because no accessible 'New' accepts this Number of arguments.

101voto

code master Points 1082

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 réellement une référence à une instance d'un objet existant sur le tas.

Soit vous n'avez jamais assigné quelque chose à la variable, soit vous n'avez jamais créé une instance de la valeur assignée à la variable, soit vous avez donné à la variable une valeur égale à Nothing / null manuellement, ou vous avez appelé une fonction qui a défini la variable à Nothing / null pour vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X