(ceci == nul) en C #!

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

 void Main() { new Derived(); } class Base { public Base(Func valueMaker) { Console.WriteLine(valueMaker()); } } class Derived : Base { ssortingng 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 comstack pas (je n’ai pas essayé la version bêta 1); J’ai appris que le chemin dur

Y a-t-il un autre moyen de rendre this == null dans C # pur?

    Cette observation a été publiée sur StackOverflow dans une autre question plus tôt dans la journée.

    La grande réponse de Marc à cette question indique que selon la spécification (section 7.5.7), vous ne devriez pas pouvoir y accéder dans ce contexte et la possibilité de le faire dans le compilateur C # 3.0 est un bogue. Le compilateur C # 4.0 se comporte correctement selon la spécification (même dans la version bêta 1, il s’agit d’une erreur de compilation):

    § 7.5.7 Cet access

    Un tel access se compose du mot réservé this .

    cet access:

     this 

    Un tel access n’est autorisé que dans le bloc d’un constructeur d’instance, d’une méthode d’instance ou d’un accesseur d’instance.

    La décompilation brute (Reflector sans optimisations) du binary du mode Debug est la suivante:

     private class Derived : Program.Base { // Methods public Derived() { base..ctor(new Func(Program.Derived.< .ctor>b__0)); return; } [ComstackrGenerated] private static ssortingng < .ctor>b__0() { ssortingng CS$1$0000; CS$1$0000 = CS$1$0000.CheckNull(); Label_0009: return CS$1$0000; } private ssortingng CheckNull() { ssortingng CS$1$0000; CS$1$0000 = "Am I null? " + ((bool) (this == null)); Label_0017: return CS$1$0000; } } 

    La méthode ComstackrGenerated n’a pas de sens. Si vous regardez l’IL (ci-dessous), il appelle la méthode sur une chaîne vide (!).

      .locals init ( [0] ssortingng CS$1$0000) L_0000: ldloc.0 L_0001: call instance ssortingng ComstackrBug.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ée, elle essaie donc de pousser une variable inexistante sur la stack.

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

    (Le réflecteur se bloque en le transformant en C #)


    EDIT : Est-ce que quelqu’un (Eric Lippert?) ldloc pourquoi le compilateur émet le ldloc ?

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

    texte alt

    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 au sein d’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.

    Je peux me tromper, mais je suis sûr que si votre object 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 

    Je ne sais pas si c’est ce que vous recherchez

      public static T CheckForNull(object primary, T Default) { try { if (primary != null && !(primary is DBNull)) return (T)Convert.ChangeType(primary, typeof(T)); else if (Default.GetType() == typeof(T)) return Default; } catch (Exception e) { throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToSsortingng() + " instead of " + typeof(T).ToSsortingng()); } return default(T); } 

    exemple: UserID = CheckForNull (Request.QuerySsortingng [“UserID”], 147);