Cela m'a complètement déconcerté.
Sub testChangeBoolean()
Dim X As Boolean ' default value is False
X = True ' X is now True
X = Not X ' X is back to False
End Sub
Mais j'essaie de basculer la propriété .FitText dans une cellule de tableau (dans Word). .FitText commence comme True.
Si je l'attribue à X:
Sub testChangeBoolean()
Dim X As Boolean ' again, default is False
X = Selection.Cells(1).FitText ' does set X to True
X = Not X ' X is still True!
End Sub
Je ne comprends tout simplement pas ce que je fais mal.
Je crois que l'explication a à voir avec la façon dont les anciens langages de programmation (WordBasic et début VBA) stockaient les valeurs entières de True et False. À cette époque, True = -1 et False = 0.
Les langages de programmation plus récents utilisent toujours 0 pour False, mais 1 pour True.
La majorité des propriétés de type booléen de Word continuent d'utiliser -1 pour True (Font.Bold, par exemple), ce qui a été source de confusion et de frustration pour les programmeurs travaillant avec Interop dans des langues plus récentes. Ainsi, à un moment donné, certains développeurs de Microsoft ont décidé d'utiliser la nouvelle méthode et ont attribué la valeur entière 1 à True pour de nouvelles fonctionnalités. Tels que FitText
.
Considérant l'exemple de code suivant, où X
est de type Boolean
et y
de type Integer
:
FitText
est True, la valeur entière est 1Not
montre que le booléen reste "True" car sa valeur entière n'est pas 0, c'est -2C'est déroutant, en effet, mais cela explique pourquoi Not
ne donne pas le résultat attendu.
Sub testChangeBoolean()
Dim X As Boolean ' again, default is False
Dim Y As Integer
X = Selection.Cells(1).FitText ' does set X to True
Y = Selection.Cells(1).FitText
Debug.Print X, Y ' result: True 1
X = Not X ' X is still True!
Y = Not Y
Debug.Print X, Y ' result: True -2
X = False
Y = True
Debug.Print X, Y ' result: False -1
End Sub
C'est à cause de la valeur Long interne provenant de cette propriété, comme expliqué par Cindy Meister. Nous devons toujours utiliser CInt pour éviter cela.
Sub testChangeBoolean2()
Dim X As Boolean ' again, default is False
X = CInt(Selection.Cells(1).FitText) ' [Fixed] does set X to True
X = Not X ' X is False!
End Sub
Pour ajouter à l'excellente réponse de Cindy, je tiens à souligner que bien que VBA dispose normalement de garanties pour contraindre les valeurs lors de l'attribution à un type de données Boolean
, cela peut être contourné. Fondamentalement, si vous écrivez une valeur aléatoire dans une adresse mémoire qui n'est pas la vôtre, vous devez vous attendre à un comportement non défini.
Pour aider à le démontrer, nous allons (ab) utiliser LSet
qui nous permet essentiellement de copier la valeur sans vraiment l'affecter.
Private Type t1
b As Boolean
End Type
Private Type t2
i As Integer
End Type
Private Sub Demo()
Dim i1 As t2
Dim b1 As t1
Dim b As Boolean
i1.i = 1
LSet b1 = i1
b = b1.b
Debug.Print b, b1.b, i1.i
Debug.Print CInt(b), CInt(b1.b), i1.i
End Sub
Notez la ligne b = b1.b
est fondamentalement équivalent à ce que nous avons fait dans le code OP
X = Selection.Cells(1).FitText
C'est-à-dire, affecter un Boolean
à un autre Boolean
. Cependant, parce que j'ai écrit au b1.b
en utilisant LSet
, en contournant les vérifications d'exécution VBA, il n'est pas contraint. Lors de la lecture du Boolean
, VBA le force implicitement dans True
ou False
, ce qui semble trompeur mais est correct car tout résultat falsifié est égal à 0
(aka False
), et tout résultat véridique n'en est pas un. Notez que le négatif pour véridique signifie que les deux 1
et -1
sont véridiques.
Si j'avais attribué le 1
à une variable Boolean
directement, VBA l'aurait forcée à -1
/True
et donc il n'y aurait pas de problème. Mais évidemment avec FitText
ou LSet
, nous écrivons essentiellement à l'adresse mémoire de manière incontrôlée, de sorte que VBA commence à se comporter étrangement avec cette variable particulière car il attend le Boolean
la variable avait déjà son contenu contraint mais ne l'était pas.