Question

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, une exception InvalidProgramException est levée. (En mode débogage, cela fonctionne bien)

Dans la version bêta 2 de VS2010, la compilation n’est pas effectuée (je n’ai pas essayé la version bêta 1); J'ai appris que la dure

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

Était-ce utile?

La solution

Cette observation a été publiée dans StackOverflow à autre question plus tôt aujourd'hui.

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

  

& # 167; 7.5.7 Cet accès

     

Un this-access est constitué du mot réservé this .

     

this-access:

this
     

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

Autres conseils

La décompilation brute (réflecteur sans optimisations) du fichier binaire en mode débogage est la suivante:

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
   .locals init (
        [0] string CS$1
    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 
) 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
; CS$1<*> = CS$1<*>.CheckNull(); Label_0009: return CS$1<*>; } private string CheckNull() { string CS$1<*>; CS$1<*> = "Am I null? " + ((bool) (this == null)); Label_0017: return CS$1<*>; } }

La méthode CompilerGenerated n'a pas de sens; si vous regardez l'IL (ci-dessous), il appelle la méthode sur une chaîne (!).

<*>

En mode Release, la variable locale est optimisée, elle essaie donc de placer une variable non existante sur la pile.

<*>

(Le réflecteur tombe en panne lorsqu'il est converti en C #)

EDIT : Quelqu'un (Eric Lippert?) sait-il pourquoi le compilateur émet le ldloc ?

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

alt text

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

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

Ce n’est pas parce que vous pouvez faire quelque chose de mauvais que cela soit un bogue que vous vous sentiez mordu.

Je peux me tromper, mais je suis presque sûr que si votre objet est null , il ne se produira 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

Vous ne savez pas si c'est ce que vous recherchez

    public static T CheckForNull<T>(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().ToString() + " instead of " + typeof(T).ToString());
        }
        return default(T);
    }

exemple: UserID = CheckForNull (Request.QueryString [" UserID &]; 147);

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top