11
votes

En .NET / C #, est nulle fortement typée?

fait null code> a un type? Comment une valeur nulle est-elle représentée en interne? Ce qui se passe dans le code suivant?

void Foo(string bar) {...}
void Foo(object bar) {...}

Foo((string)null);


0 commentaires

7 Réponses :


2
votes

Il appellera FOO (barre de cordes).

Vous pouvez lancer Null Fine.


0 commentaires

1
votes

Le mot clé NULL est un littéral qui représente une référence nulle, une référence qui ne fait référence à aucun objet. NULL est la valeur par défaut des variables de type de référence. De MSDN . Donc, la valeur par défaut de la chaîne dans votre exemple.
xxx pré>

Ce que vous faites est équivalent à l'utilisation par défaut selon ci-dessus: P>

int equal = string.Compare((string)null, default(string));


0 commentaires

2
votes

Lorsque vous définissez un objet de référence sur null , le pointeur (derrière) pointe sur un endroit spécial en mémoire désigné null . Alors, lorsque vous lancez sur null , vous créez vraiment un pointeur du type spécifique qui pointe vers null .

Comme démontré par d'autres (1) (2) , cela ne semble pas Soyez le cas car le compilateur résout la surcharge émettant de l'IL selon le NULL NULL

Je sais que les variables de référence ont un type associé à eux. Je pensais que cela serait derrière ce null casting mais j'avais tort.

the ldnull opcode pousse une référence nulle (type O) sur la pile. Et même si cette référence nulle a un type associé à celui-ci, le appel accepte cette référence comme argument valide de chaîne . Au moins, c'est ma compréhension. Si quelqu'un a des corrections à cela, n'hésitez pas à me corriger.


0 commentaires

17
votes

La distribution à String dans votre exemple exemple ne donne pas le type null un type, comme null ne peut pas avoir de type lui-même. Si vous souhaitez la preuve, alors exécutez le code suivant où vous pouvez voir que null est toujours égal à lui-même, quel que soit le type de variable qu'il a été attribué est: xxx

Qu'est-ce que la distribution est indiquée au compilateur qui surcharge à choisir. Comme null n'a pas de type, il ne sait pas s'il faut choisir la surcharge qui prend un objet objet ou a chaîne car la valeur pourrait être la valeur. interprété comme non plus. Donc, vous l'aidez en disant «Voici une valeur nulle qui devrait être traitée comme si c'était une chaîne».


Si vous voulez voir ce qui se passe en dessous, puis regardez le Il de votre code. Le bit pertinent pour l'appel de la méthode est quelque chose comme les éléments suivants dans Textual IL (en fonction de votre espace de noms et de votre nom de classe, etc.): xxx

donc tout ce qui se passe est qu'un null est chargé sur la pile, puis celui-ci est consommé par la surcharge qui prend la chaîne, car la résolution de surcharge est effectuée au moment de la compilation afin que la méthode appelle soit cuite à l'IL.

Si vous voulez Voir ce que ldnull fait et pourquoi il est différent de simplement utiliser quelque chose comme ldc.i4.0 pour charger un zéro sur la pile, puis voir Cette réponse (Si vous ne voulez pas suivre le lien, la raison est que c'est un taille-agnostic zéro qui n'existe autrement pas dans le CLR).


3 commentaires

Alors, que sera exactement sur la pile lorsque je parle de null ?


@Matt - édité pour ajouter plus de détail de bas niveau. Est-ce suffisant?


@Greg: Merci - j'étais occupé au travail alors n'avait pas le temps de vérifier l'IL et l'ECMA SPEC-moi-même. Cela a gratté ma démangeaison intellectuelle.



1
votes

null est un marqueur, il n'a pas de type de données.Lors que vous attribuez .NULL à un champ ou à une variable, la valeur change sur NULL, mais le type de données du champ ou de la variable ne change pas.

La raison de l'attribution de type de chaîne à NULL dans votre exemple, je pense que la méthode de la sorcière sera utilisée (dans ce cas "Void FOO (String Bar) {...}" Parce que c'est la méthode qui accepte cordes comme arguments.)

Si vous auriez appelé foo ((objet) null); L'autre méthode aurait été utilisée. ("Void Foo (Object Bar) {...}")


0 commentaires

6
votes

NULL n'a pas de type, et "et" et dans l'extrait de code, est le casting utilisé simplement par le compilateur C # pour décider quelle surcharge à appeler, et il n'y a pas vraiment de casting de NULL? " est exactement ce qui se passe. Regardons l'IL généré.

  IL_0001:  ldnull
  IL_0002:  call       void ConsoleApplication1.Program::Foo(object)


0 commentaires

1
votes

Le type de la valeur null est défini par ECMA-334 comme suit:

11.2.7 Le type NULL

Le littéral null (§9.4.4.6) évalue à la null valeur, qui est utilisée pour désigner un Référence ne pointant sur aucun objet ou une matrice ou l'absence d'une valeur. Le type null a une valeur unique, qui est la valeur null. D'où un expression dont le type est le type null peut évaluer uniquement la valeur null. Il n'y a aucun moyen d'écrire explicitement le type nul et, donc, aucun moyen pour l'utiliser dans un type déclaré.

Le type NULL est le type inférieur de la hiérarchie de type - l'opposé de l'objet; Le type NULL peut être considéré comme étant un sous-type de type nullable, car la valeur null peut être utilisée partout où une expression nullable se produit.

Cela crée une faiblesse dans le système de type, car cela signifie que toute opération dont le récepteur est un type nullable pourrait être null, et l'opération peut échouer au moment de l'exécution d'une exception. Dans un système de type solide, les opérations fournies par un type sont garanties si le récepteur est de ce type (c'est-à-dire que vous ne recevriez pas une exception de pointeur NULL, qui dit vraiment que le type null ne met pas en œuvre la méthode que vous avez Invoqué dessus, bien que la valeur nulle puisse résulter de l'expression de tout type que vous pensiez utiliser).

Dans votre code, les méthodes sont surchargées et le type statique de l'expression produisant l'argument est utilisé pour la résolution de la surcharge. En raison de la fonte à la chaîne, l'expression a une chaîne de caractères (le type NULL étant un sous-type de chaîne ceci est à la hausse si sûre selon le système de type C #). En première approximation, le compilateur sélectionne la surcharge la plus spécifique visible, donc chose la version de chaîne de FOO plutôt que la version d'objet.


0 commentaires