129 votes

(ceci == null) en C #!

En raison d'un bogue corrigé dans C # 4, le programme suivant imprime true . (Essayez-le dans LINQPad)

 void Main() { new Derived(); }

class Base {
    public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
    string CheckNull() { return "Am I null? " + (this == null); }
    public Derived() : base(() => CheckNull()) { }
}
 

Dans VS2008 en mode Release, il génère une exception InvalidProgramException. (En mode de débogage, cela fonctionne bien)

Dans VS2010 Beta 2, il ne compile pas (je n'ai pas essayé la version bêta 1); J'ai appris que le chemin dur

Existe-t-il un autre moyen de rendre this == null en C # pur?

73voto

Mehrdad Afshari Points 204872

Cette observation a été posté sur StackOverflow dans une autre question , plus tôt aujourd'hui.

Marc's grande réponse à cette question indique que, selon les spécifications (article 7.5.7), vous ne devriez pas être en mesure d'accéder this dans ce contexte et la capacité de le faire en C# 3.0 compilateur est un bug. C# 4.0 compilateur se comporte correctement selon la spécification (encore en version Bêta 1, c'est une erreur de compilation):

§ 7.5.7 Cet accès

Un ce-accès consiste en le mot réservé this.

cet accès:

this

Un cet accès n'est autorisé que dans le bloc d'un exemple de constructeur, une méthode d'instance, ou d'une instance de l'accesseur.

24voto

SLaks Points 391154

Les premières décompilation (Réflecteur sans optimisations) de Debug mode binaire est:

private class Derived : Program.Base
{
    // Methods
    public Derived()
    {
        base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
        return;
    }

    [CompilerGenerated]
    private static string <.ctor>b__0()
    {
        string CS$1$0000;
        CS$1$0000 = CS$1$0000.CheckNull();
    Label_0009:
        return CS$1$0000;
    }

    private string CheckNull()
    {
        string CS$1$0000;
        CS$1$0000 = "Am I null? " + ((bool) (this == null));
    Label_0017:
        return CS$1$0000;
    }
}

Le CompilerGenerated méthode n'est pas logique; si vous regardez le IL (ci-dessous), c'est l'appel de la méthode sur un nul chaîne de caractères (!).

   .locals init (
        [0] string CS$1$0000)
    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: stloc.0 
    L_0007: br.s L_0009
    L_0009: ldloc.0 
    L_000a: ret

En mode Release, la variable locale est optimisé à l'extérieur, donc il essaie de pousser un non-existant variable sur la pile.

    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret

(Réflecteur se bloque lors de la mise en C#)


EDIT: quelqu'un (Eric Lippert?) savoir pourquoi le compilateur émet l' ldloc?

11voto

leppie Points 67289

J'ai eu ça! (et eu des preuves aussi)

texte alt

10voto

Will Points 76760

Ce n'est pas un "bug". C'est vous abusant du système de type. Vous n'êtes jamais censé transmettre une référence à l'instance actuelle ( this ) à quiconque dans un constructeur.

Je pourrais également créer un "bug" similaire en appelant une méthode virtuelle dans le constructeur de la classe de base.

Juste parce que vous pouvez faire quelque chose de mal ne signifie pas que c'est un bug quand vous en avez un peu.

4voto

Dan Tao Points 60518

Je peux me tromper, mais je suis certain que votre objet est null il n'y aura jamais de scénario où this s'applique.

Par exemple, comment appelleriez-vous CheckNull ?

 Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
 

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