2016-12-15 4 views
0

J'utilise Nullable(Of Integer) et vient d'être piqué par Nothing étant casté à 0. C'est exactement ce que je ne veux pas lorsque vous utilisez Nullable(Of Integer).Odd interaction de "If" et Nullable (Of Integer)

func1 ci-dessous ne se comporte pas comme je m'attendais. Je peux l'obtenir pour faire ma volonté en l'amendant (voir func2). Mais je ne vois pas pourquoi cela devrait être nécessaire (et je pense que je pourrais avoir du mal à m'en souvenir).

Pourquoi func1 ne fait-il pas ce que je veux? Je pense que j'ai déjà rencontré ça, et je préférerais ne pas le revoir.

Function func1(parameter As Integer) As Nullable(Of Integer) 
    Return If(parameter > 10, parameter, Nothing) 
End Function 

Function func2(parameter As Integer) As Nullable(Of Integer) 
    Return If(parameter > 10, parameter, DirectCast(Nothing, Integer?)) 
End Function 

Sub Main 
    ' Should be True 
    System.Console.WriteLine(func1(11).HasValue) 
    System.Console.WriteLine(func2(11).HasValue) 
    System.Console.WriteLine() 

    ' Should be False 
    System.Console.WriteLine(func1(9).HasValue) 
    System.Console.WriteLine(func2(9).HasValue)  
End Sub 

Les résultats que je reçois (en cours d'exécution cela en LINQPad) sont:

True 
True 

True 
False 

Répondre

2

Faits importants dans votre cas:

  • méthode Inline If prévu que les deux "vrai" et « faux "les expressions doivent retourner le même type.
  • Nothing est la valeur par défaut du type.
    Pour Integer, il s'agit de 0.
    Pour le type de référence, il est null

Dans la première méthode méthode en ligne If prévoit que « Faux » expression doit retourner un Integer, parce que le compilateur ne peut pas décider le type de rendement fondé sur Nothing, il utilisera type produit par « True » expression. Donc Nothing va produire la valeur par défaut du type Integer qui est 0. Dans la seconde méthode, les deux paramètres ont des types retournés explicitement déclarés, où Integer peut être implicitement converti en Nullable, de sorte que le compilateur renvoie Nullable comme résultat de la méthode If.

Le rôle clé de votre problème est la méthode en ligne If. Qui utilise Nothing comme valeur par défaut de Integer.

Si vous réécrivez comme d'habitude If .. Else alors tout fonctionne sans DirectCast

Private Function GetNullableInteger(parameter As Integer) As Integer? 
    If parameter > 10 Then 
     Return parameter 
    Else 
     Return Nothing 
    End If 
End Function 
1

Pour expliquer ce qui se passe ici, je vais commencer par enlever la partie abrégée de votre code qui peut aider à mon explication.

Les entiers de VB.net ne peuvent pas être affectés en utilisant Null ou DBNull. Il est possible de l'affecter en utilisant Nullable-of-T comme vous l'avez fait. Cependant, dès que vous créez l'objet Nullable-ish, il peut être évalué à 0.

Considérez ce qui suit

dim x as Integer = nothing 'evaluates to x=0 

Ainsi, lorsque votre fonction fonctionne, vous utilisez DirectCast() pour retourner un entier annulable-ish, qui évalue ensuite ne pas être annulable par func2

Function func1(parameter As Integer) As Nullable(Of Integer) 
    Return If(parameter > 10, parameter, Nothing) 
End Function 

Function func2(parameter As Integer) As Nullable(Of Integer) 
    Return If(parameter > 10, parameter, DirectCast(Nothing, Nullable(of Integer))) 
End Function 

Sub Main() 
    ' Should be True 
    System.Console.WriteLine(func1(11).HasValue) 
    System.Console.WriteLine(func2(11).HasValue) 
    System.Console.WriteLine() 

    ' Should be False 
    System.Console.WriteLine(func1(9).HasValue) 
    System.Console.WriteLine(func2(9).HasValue) 
    Console.ReadLine() 
End Sub 
+0

Je vais modifier ma réponse. –

+0

Brainmelt. Merci @Fabio. Je l'ai dit dans ma réponse :) –

0

Voici func1 réécrit. Notez qu'il n'y a pas besoin de casting.

Function func1(parameter As Integer) As Nullable(Of Integer) 
    Dim rv As New Nullable(Of Integer) 
    If parameter > 10 Then 
     rv = parameter 
    End If 
    Return rv 
End Function 

L'opérateur Si, Si (foo, foo = true, foo = false), doit être utilisé avec parcimonie, car il est plus lent que la norme Si construction.

éditer: La déclaration concernant l'opérateur If est incorrecte.

Merci à Chris.

+1

Avez-vous une source pour cela? J'ai fait un benchmark simple qui a couru environ 1000000 itérations du code, en écartant les premiers 1000 ou plus. Résultat: 'Si opérateur': 0.0000116 ms,' If Then Else': 0.0000093 ms. Ainsi, alors que l'opérateur 'If' était légèrement plus lent, il ne semble pas significatif du tout. Le code d'étalonnage utilisé un chronomètre pour ses horaires. –

+1

Mes temps dans mon commentaire ci-dessus n'incluaient pas l'utilisation de Nullable (Of Integer) ou 'DirectCast'. Quand j'ai changé le code sous test pour l'inclure, les délais ont augmenté, mais étaient compatibles avec le premier test: 'If': 0.0000345' If Else' 0.0000333. Je suppose que l'augmentation du temps était due à 'DirectCast'. –

+0

@ChrisDunaway - J'ai peut-être pensé à IIf. – dbasnett