Dans la
première partie de l'article, le sujet de la supériorité de VB.NET sur C # en termes de note TIOBE a trouvé une réponse vivante dans les commentaires. Par conséquent, sur les
conseils d' AngReload, regardons les
tendances de StackOverflow.

C # est toujours fort! La révolution dont on a tant parlé la dernière fois est annulée! Hourra, camarades! Ou pas? La note TIOBE est basée sur les requêtes des moteurs de recherche, et la note SO est basée sur les balises des questions posées. Peut-être que les développeurs de VB.NET, qui incluent de nombreuses personnes qui n'ont pas de spécialités, ne connaissent tout simplement pas l'existence de StackOverflow? Ou y être arrivé via Google, ou même Bing, ne comprends pas comment poser une question? Ou peut-être qu'ils ont suffisamment de documentation Miscrosoft, et toutes les quelques questions ont déjà été répondues.
D'une manière ou d'une autre, la part de VB.NET est perceptible et stable, mais pas en premier lieu en termes de volume. Et, bien sûr, un tel résultat n'aurait pas été possible sans une solide équipe de concepteurs et de développeurs de langage. Vous trouverez ci-dessous la deuxième partie de la traduction d'un article d'un membre de cette équipe,
Anthony Green .
Table des matières
Conversions
34. Transformations booléennes
La conversion de la valeur
Boolean True
en n'importe quel type numérique signé donne
-1
, et en tout type non signé, elle donne la valeur maximale pour ce type, alors qu'en C # il n'y a pas de telles conversions. Cependant, la méthode
Convert.ToInt32
, par exemple, convertit
True
en
1
, et c'est ainsi qu'elle est le plus souvent représentée en
IL
. Dans le sens opposé, tout nombre autre que
0
est converti en
True
.
Pourquoi? La raison pour laquelle VB préfère utiliser de
-1
à
1
est que la négation au niveau du bit de 0 (tous les bits sont définis à 0) dans n'importe quelle langue est
-1
(tous les bits sont définis à
1
), donc l'utilisation de cette valeur combine logique et bit à bit des opérations telles que
And
,
Or
et
Xor
.
Les conversions vers et depuis les lignes "Vrai" et "Faux" sont également prises en charge (bien sûr, insensible à la casse).
35. Les conversions entre les types Enum ainsi qu'entre les types Enum et leurs types de base sont totalement illimitées, même si Option Strict est réglé sur On
D'un point de vue philosophique, un langage fait référence aux types
Enum
plutôt comme un ensemble de constantes nommées d'un type entier de base. L'endroit où cela est le plus évident est l'égalité. Il est toujours permis de comparer n'importe quel entier avec une valeur d'énumération, alors qu'en C # cela donne une erreur.
Heure du conte
: L'API Roslyn a subi de nombreuses révisions internes. Mais dans chacun d'eux, une énumération
SyntaxKind
été allouée pour chaque langue, qui vous indique quelle syntaxe le nœud représente (par exemple,
IfStatement
,
TryCastExpression
). Une fois, un développeur a utilisé une API qui a essayé d'abstraire de la langue et a renvoyé l'une des valeurs
SyntaxKind
, mais uniquement en tant
Integer
, et sans recevoir d'erreurs lors de la comparaison d'
Integer
brut et de
SyntaxKind
, ce développeur est immédiatement venu dans mon bureau et s'est plaint:
«int is détail de la mise en œuvre, j'aurais dû être obligé de faire un casting! " .
Au fil des ans, lors de la prochaine révision de l'API, nous avons complètement supprimé les propriétés (
Property Kind As SyntaxKind
), qui pointaient vers un type spécifique à la langue, et toutes les API ont commencé à renvoyer
Integer
. Tout le code C # s'est cassé et tout le code VB a continué de fonctionner comme si de rien n'était.
Un peu plus tard, nous avons décidé de renommer cette propriété en
RawKind
et d'ajouter des méthodes d'extension spécifiques au langage
Kind()
. Tout le code C # s'est cassé car des parenthèses étaient nécessaires pour appeler des méthodes, mais comme elles n'étaient pas nécessaires dans VB, tout le code VB a continué à fonctionner comme si de rien n'était.
36. La vérification du débordement / débordement négatif pour l'arithmétique entière est entièrement contrôlée par l'environnement de compilation (paramètres du projet), mais VB et C # utilisent des valeurs par défaut différentes; dans VB, la vérification du débordement est activée par défaut
Les types intégraux ont une plage, donc, par exemple, l'
Byte
peut représenter des valeurs de 0 à 255. Que se passe-t-il donc lorsque vous ajoutez l'
Byte
1 à l'
Byte
255? Si la vérification de dépassement / dépassement est désactivée, la valeur défile jusqu'à 0. Si le type est signé, il défile jusqu'au nombre négatif le plus bas (par exemple, -128 pour
SByte
). Cela indique très probablement une erreur dans votre programme. Si la vérification de dépassement / dépassement est activée, une exception est levée. Pour comprendre ce que je veux dire, jetez un œil à cette boucle
For
inoffensive.
Module Program Sub Main() For i As Byte = 0 To 255 Console.WriteLine(i) Next End Sub End Module
code source githubPar défaut, cette boucle lèvera une exception dans VB (puisque la dernière itération de la boucle va au-delà de la bordure d'
Byte
. Mais avec la vérification de débordement désactivée, elle boucle car après 255, je redeviens 0.
Le sous-dépassement est la situation inverse lorsque la soustraction en dessous de la valeur minimale pour le type entraîne la valeur maximale.
Une situation de débordement plus courante consiste simplement à ajouter deux chiffres. Prenez les nombres 130 et 150, tous deux en
Byte
. Si vous les assemblez, la réponse est 280, ce qui ne rentre pas dans l'octet. Mais votre processeur ne le perçoit pas. Au lieu de cela, il rapporte que la réponse est 24.
Soit dit en passant, cela n'a rien à voir avec les conversions. L'ajout de deux octets donne un octet; c'est juste la façon dont les mathématiques binaires fonctionnent. Bien que vous puissiez également obtenir un débordement en effectuant une conversion, par exemple, lorsque vous essayez de convertir Long en entier. Sans vérifier le débordement, le programme coupe simplement les bits et les trucs supplémentaires autant qu'il tient dans cette variable.
Quelle est la différence? Performance. La vérification du CLR pour le débordement nécessite un peu plus de temps de calcul par rapport à l'option de non-vérification, comme toutes les autres vérifications de sécurité. VB est basé sur la philosophie selon laquelle la productivité des développeurs est plus importante que les performances de calcul, donc par défaut, le contrôle de sécurité est activé.
Aujourd'hui, l' équipe de développement C #
peut prendre une décision différente sur les paramètres par défaut du projet, mais étant donné que les premiers développeurs C # sont venus de développeurs C / C ++, ce groupe de personnes exigerait probablement que le code ne fasse rien de plus, ce qui pourrait coûter des cycles de processeur ;
c'est une différence philosophique difficile .
Nuance: même si la vérification de dépassement / dépassement est désactivée, la conversion des
NaN
PositiveInfinity
,
NegativeInfinity
,
NaN
des types
Single
ou
Double
en
Decimal
lèvera une exception, car aucune de ces valeurs ne peut en principe être représentée en Decimal.
37. La conversion de nombres à virgule flottante en types entiers utilise les arrondis bancaires plutôt que la troncature
Si vous convertissez 1,7 en entier en VB, le résultat sera 2. En C #, le résultat sera 1. Je ne peux rien dire sur les règles mathématiques en dehors de l'Amérique, mais lorsque je passe d'un nombre réel à un entier, je arrondis instinctivement. Et aucun de ceux que je connais en dehors du cercle des programmeurs ne croit que l'entier le plus proche de 1,7 est 1.
Il existe en fait plusieurs méthodes d'arrondi, et le type d'arrondi utilisé dans VB (et dans la méthode Math.Round) est appelé arrondi par banque ou arrondir les statisticiens par défaut. Son essence est que pour un nombre au milieu entre deux entiers, VB arrondit au nombre pair le plus proche. Donc 1,5 est arrondi à 2 et 4,5 est arrondi à 4. Ce qui ne fonctionne pas vraiment comme on nous a enseigné à l'école - on m'a appris à arrondir de 0,5 (techniquement, arrondir de zéro à côté). Mais, comme son nom l'indique, l'arrondi bancaire a l'avantage qu'avec un grand nombre de calculs, vous divisez en arrondissant en deux et ne donnez pas toujours ou ne gardez pas toujours de l'argent. En d'autres termes, sur un grand ensemble, cela limite la distorsion des données à l'écart statistique ultime.
D'où vient la différence? L'arrondi est plus intuitif et pratique, tronquant plus rapidement. Si vous envisagez d'utiliser VB dans les applications LOB, et en particulier dans les applications telles que les macros Excel qui s'exécutent sur VBA, la simple suppression de décimales peut entraîner ... des problèmes.
Je pense qu'il est évident que la méthode de conversion est toujours une question controversée et devrait être indiquée explicitement, mais si vous devez en choisir une seule ...
38. Ce n'est pas une erreur de convertir des classes NotInheritable vers / depuis des interfaces qu'ils n'implémentent pas au moment de la compilation
De manière générale, si vous recherchez dans une classe NonInheritable une implémentation d'interface, vous pouvez comprendre au moment de la compilation si une telle conversion est possible car vous connaissez toutes les interfaces de ce type et tous ses types de base. Si le type est hérité, vous ne pouvez pas être sûr qu'une telle conversion est impossible, car le type de l'objet d'exécution référencé peut en fait avoir un type plus dérivé qui implémente cette interface. Cependant, il existe une exception en raison de l'interopérabilité COM, lors de la compilation, il peut ne pas être visible que le type a quelque chose à voir avec l'interface, mais au moment de l'exécution, il le sera. Pour cette raison, le compilateur VB génère un avertissement dans de tels cas.
Pourquoi? VB et COM ont grandi ensemble quand ils étaient enfants dans le vieux quartier. Il existe donc plusieurs solutions dans la conception de langage dans lesquelles VB accorde une grande attention aux choses qui n'existaient que dans COM au moment de la sortie de .NET 1.0.
39. Essayer de décompresser (décompresser) null dans un type significatif entraîne une valeur par défaut du type, pas une NullReferenceException
Je crois que techniquement, cela est également vrai pour les types de référence, mais oui:
CInt(CObj(Nothing)) = 0
Pourquoi? Parce que
CInt(Nothing) = 0
, et le langage a tendance à être quelque peu cohérent, que vous ayez tapé ou non vos variables. Cela s'applique à n'importe quelle structure, pas seulement aux types significatifs intégrés. Voir la
justification au # 25 pour plus de détails.
40. Unboxing prend en charge les conversions de type primitif
En VB et en C #, vous pouvez convertir
Short
en
Integer
, mais qu'en est-il si vous essayez de convertir un
Short
emballé en
Integer
? Dans VB,
Short
sera d'abord décompressé puis converti en
Integer
. En C #, sauf si vous décompressez manuellement court avant de convertir en
int
, une
InvalidCastException
sera levée.
Cela s'applique à toutes les conversions internes, c'est-à-dire les types numériques compressés, les conversions entre les chaînes et les types numériques, les chaînes et les dates (oui, Decimal et Date sont des types primitifs).
Pourquoi? Encore une fois, pour garantir un comportement cohérent, que votre programme soit entièrement tapé, tapé en tant qu'objet ou en cours de refactorisation d'une option à une autre. Voir
# 39 ci-dessus.
41. Il y a des conversions entre String
et Char
String
convertie en Char
, représentant son premier caractère.Char
converti en String
seule manière raisonnable.
Parce que personne sauf moi ne se souvient de la syntaxe d'un littéral de caractère en VB (et il ne devrait pas).
42. Il existe des conversions entre String
et Char
array
String
convertie en un tableau de caractères composé de tous ses caractères.- Le tableau
Char
est converti en une String
composée de tous ses éléments.
Pour être précis: ces transformations créent de nouveaux objets, vous n'avez pas accès à la structure
String
interne.
Histoire amusante: j'ai trouvé (ou peut-être signalé, et je faisais des recherches) un changement de rupture entre .NET 3.5 et 4.0, car entre ces versions, l'équipe .NET a ajouté le modificateur
ParamArray
au deuxième
String.Join
surcharge
String.Join
, qui prend un tableau de chaînes . Les hypothèses exactes sont perdues dans le temps (probablement pour le mieux), mais, comme je le crois, la raison est qu'avec le modificateur
ParamArray
vous pouvez maintenant convertir un tableau
Char
en une chaîne et le passer en tant qu'élément séparé au tableau de paramètres. Thème amusant.
43 et 44. Les conversions de String en types numériques et date prennent en charge la syntaxe littérale (généralement)
CInt("&HFF") = 255
CInt("1e6") = 1_000_000
CDate("#12/31/1999#") = #12/31/1999#
Cela fonctionne avec les préfixes de base et permet d'utiliser un moyen très pratique pour convertir une entrée hexadécimale (ou octale) en un nombre:
CInt("&H" & input)
. Malheureusement, cette symétrie se dégrade au moment d'écrire ces lignes, car le runtime VB n'a pas été mis à jour pour prendre en charge le préfixe binaire & B ou le
1_000
groupe à
1_000
chiffres, mais j'espère que cela sera corrigé dans la prochaine version. La notation scientifique fonctionne, mais sans suffixe de type, et les conversions de date prennent également en charge les formats de date standard, donc le format JSON utilisé dans ISO-8601 fonctionne également:
CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM#
.
Pourquoi? Je ne connais pas d'autre raison que la commodité. Mais je voudrais
vraiment offrir un support pour d'autres formats courants qui sont presque omniprésents dans le réseau aujourd'hui, tels que #FF, U + FF, 0xFF. Je pense que cela pourrait grandement faciliter la vie dans certains types d'applications ...
45. AUCUNE conversion entre les types Char
et Entier
QUOI?!?!?Après avoir lu toutes ces transformations supplémentaires, êtes-vous surpris? VB interdit les conversions entre
Char
et
Integer
:
CInt("A"c)
ne compile pas.CChar(1)
ne compile pas.
Pourquoi? On ne sait pas ce qui va se passer. Habituellement, VB dans de telles situations utilise une approche pragmatique et / ou intuitive, mais pour l'expression
CInt("1")
je pense que la moitié des lecteurs s'attendraient au chiffre 1 (valeur de caractère 1), et l'autre moitié s'attendrait au chiffre 49 (code ASCII / UTF pour caractère 1). Au lieu de faire le mauvais choix dans la moitié des cas, VB a des fonctions spéciales pour convertir les caractères en codes ASCII / Unicode et vice versa,
AscW
et
ChrW
respectivement.
Expressions
46. Rien <> null
Le littéral
Nothing
dans VB ne signifie pas
null . Cela signifie
"la valeur par défaut pour le type pour lequel
il est utilisé", et il se trouve que pour les types de référence, la valeur par défaut est nulle. La différence n'a d'importance que lorsqu'elle est utilisée dans un contexte dans lequel:
- Rien ne prend un type significatif, et ...
- Il ne ressort pas clairement du contexte qu'il le fait.
Regardons quelques exemples qui illustrent ce que cela signifie.
Le premier, peut-être un peu étrange, mais je ne pense pas que la plupart des gens seront comblés par la compréhension que ce programme imprimera "Vrai":
Module Program Sub Main() Dim i As Integer = 0 If i = Nothing Then Console.WriteLine("True") End If End Sub End Module
code source githubLa raison est assez simple: vous comparez
Integer (0)
avec la valeur par défaut de son type (également 0). Le problème se produit dans VB2005 / 2008 lorsque vous ajoutez des types significatifs nullables. Jetez un œil à cet exemple:
Module Program Sub Main() Dim i = If(False, 1, Nothing) End Sub End Module
code source githubCompris, comment quelqu'un peut-il suggérer que le type
i
est un
Integer?
(
Nullable(Of Integer)
). Mais ce n'est pas le cas, car
Nothing
obtient le type à partir du contexte, et le seul type dans ce contexte provient du deuxième opérande, et il s'agit d'un simple
non-nullable Integer
(techniquement,
Nothing
n'a jamais de type). Une autre façon de voir ce problème est avec l'exemple suivant:
Module Program Sub Main() M(Nothing) End Sub Sub M(i As Integer) Console.WriteLine("Non-nullable") End Sub Sub M(i As Integer?) Console.WriteLine("Nullable") End Sub End Module
code source githubIci encore, intuitivement, il semble que
Nothing
ajoute un indice «nullable» et que le langage sélectionne une surcharge qui accepte
nullable
, mais ce n'est pas le cas (sélectionne
non-nullable
, car il est «le plus spécifique»). Au minimum, on peut supposer que, comme null en C #, l'expression
Nothing
ne s'applique pas du tout à
Integer
, et que la surcharge nullable sera sélectionnée par la méthode d'exception, mais cela est à nouveau basé sur la mauvaise idée que
Nothing = null (Is null?)
.
Nuance: Une nouvelle expression
default
a été ajoutée en C # 7.1 qui correspond à
Nothing
en VB. Si vous réécrivez les trois exemples ci-dessus en C # en utilisant
default
au lieu de
null
,
vous obtenez exactement le même comportement .
Que peut-on faire à ce sujet? Il y a plusieurs suggestions, mais aucune n'a encore gagné:
- Afficher un avertissement à chaque fois que
Nothing
converti en un type significatif et qu'il n'est pas null
dans un type significatif nullable
. - Développez magnifiquement
Nothing
à 0
, 0.0
, ChrW(0)
, False
, #1/1/0001 12:00:00 AM#
ChrW(0)
#1/1/0001 12:00:00 AM#
ou New T
(la valeur par défaut pour toute structure) à chaque fois que sa valeur à l'exécution est l'une des énumérés ci-dessus. - Ajoutez une nouvelle syntaxe signifiant "Null, non, vraiment!" Comme
Null
ou Nothing?
- Ajoutez une nouvelle syntaxe sous la forme d'un suffixe (?) Qui encapsule la valeur dans nullable pour aider à déduire le type, par exemple
If(False, 0?, Nothing)
- Ajoutez des opérateurs de conversion Nullable pour les types intégrés pour faciliter la fourniture d'indices pour l'inférence de type, par exemple,
If (False, CInt? (0), Nothing)
J'aimerais avoir votre avis dans les commentaires et / ou
sur Twitter .
Donc, pour résumer:
- Autrefois - VB6 et VBA ont "Nothing", "Null", "Empty" et "Missing", ce qui signifie des choses différentes.
- 2002 - dans VB.NET il n'y a que
Nothing
(la valeur par défaut dans un contexte spécifique), et en C # - seulement null
. - 2005 - C # ajoute
default(T)
(une valeur par défaut de type T
), car les génériques nouvellement ajoutés créent une situation où vous devez initialiser une valeur, mais vous ne savez pas s'il s'agit d'un type de référence ou significatif; VB ne fait rien car ce script est déjà fermé par Nothing
. - 2017 - C # ajoute la
default
(valeur default
dans le contexte) car il existe de nombreux scénarios dans lesquels la spécification de T
redondante ou impossible
VB continue de résister à l'ajout d'une expression
Null
(ou équivalent) car:
- La syntaxe va briser le changement.
- La syntaxe ne cassera pas le changement, mais selon le contexte, cela signifiera différentes choses.
- La syntaxe sera trop discrète (par exemple,
Nothing?
); Imaginez que vous ayez besoin de parler à voix haute de Nothing
et de Nothing?
pour expliquer quelque chose à une personne. - La syntaxe peut être trop laide (par exemple
Nothing?
). - Le script d'expression nulle est déjà fermé par
Nothing
, et cette fonction sera complètement redondante la plupart du temps. - Partout, toute la documentation et toutes les instructions doivent être mises à jour pour recommander l'utilisation d'une nouvelle syntaxe, qui déclare fondamentalement
Nothing
obsolète pour la plupart des scénarios. Nothing
et Null
se comporteront toujours de la même manière lors de l'exécution en ce qui concerne les liaisons tardives, les transformations, etc.- Cela peut être comme une arme à feu dans un coup de couteau.
Quelque chose comme ça.
Hors sujet (mais lié)Voici un exemple très similaire au second ci-dessus, mais sans inférence de type:
Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) End Sub End Module
code source githubCe programme affiche 0. Il se comporte exactement de la même manière que le deuxième exemple, pour la même raison, mais illustre un problème distinct, quoique connexe. Intuitivement, qu'est-ce que
Dim i as Integer? = If(False, 1, Nothing)
Dim i as Integer? = If(False, 1, Nothing)
se comporte comme
Dim i As Integer? : If False Then i = 1 Else i = Nothing
Dim i As Integer? : If False Then i = 1 Else i = Nothing
. Dans ce cas, ce n'est pas le cas, car l'expression conditionnelle
(If)
ne «transmet» pas les informations du type final à ses opérandes. Il s'avère que cela décompose toutes les expressions dans VB qui s'appuient sur ce qu'on appelle le typage final (contextuel) (
Nothing
,
AddressOf
, un tableau de littéraux, d'expressions lambda et de chaînes interpolées) avec des problèmes allant de la décompilation en général à la création silencieuse de valeurs incorrectes pour levant bruyamment des exceptions. Voici un exemple d'une option non compilée:
Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) Dim operation As Func(Of Integer, Integer, Integer) = If(True, AddressOf Add, AddressOf Subtract) End Sub Function Add(left As Integer, right As Integer) As Integer Return left + right End Function Function Subtract(left As Integer, right As Integer) As Integer Return left - right End Function End Module
code source githubCe programme ne se compilera pas. Au lieu de cela, il signale une erreur dans l'expression
If
qu'il ne peut pas déterminer le type d'expression lorsque les deux expressions
AddressOf
sont
AddressOf
destinées à recevoir des délégués
Func(Of Integer, Integer, Integer)
.
,
Nothing
null (),
Nothing
nullability
()
If(,,)
Nothing
( ) () — ,
.
47. ;
«3»:
Module Program Sub Main() Dim i As Integer = 3 M((i)) Console.WriteLine(i) End Sub Sub M(ByRef variable As Integer) variable = -variable End Sub End Module
GitHubC# «-3». , VB — ,
. ,
M(3)
,
M(i)
,
i
, . C# ( ) , M .
Pourquoi? VB
. Quick Basic (Copyright 1985), . ,
2002 , .
№1: « » , Visual Basic .NET.
№2: Roslyn ( ,
( ) ( )), : . C# ,
((a + b) * c a + (b * c))
. , C#, C++, , , , . : « VB?» « C#?»
source.roslyn.io —
BoundParenthesized
VB C#. , , .
48. Me
—
VB.NET
Me
. , - , — , Me Structure . Me . C#
this
,
this
.
49.
VB, , :
Class C Sub M() Extension() End Sub End Class Module Program Sub Main() End Sub <Runtime.CompilerServices.Extension> Sub Extension(c As C) End Sub End Module
GitHubC# ( something.Extension). , C#, ,
this.Extension()
.
Pourquoi? ,
'Me.'
, , , , . VB.NET . , .
50. (Static imports will not merge method groups)
VB « » (Java-, C# VB). ,
Imports System.Console
WriteLine()
. 2015 C# . VB Shared- ,
System.Console
System.Diagnostics.Debug
,
WriteLine
, . C# , , .
Pourquoi? , , VB , C# ( ). , ( , ), … , .
, VB , VB , , , , , (
#6 ). VB . , VB 2002 .
51 52. (Partial-name qualification & Smart-name resolution)
:
- , — ( ).
System
System.Windows.Forms
— , , System
System.Windows
System.Windows
System.Windows.Forms
. - , , , .
System
Windows
, Windows
Form
.
, , . . VB Imports ,
using
C# .
, VB
System
,
System
,
System
. , . ,
ExtensionAttribute
,
<Runtime.CompilerServices.Extension>
<System.Runtime.CompilerServices.Extension>
.
C# .
using System
System.Threading
Threading
.
, C# , . ,
System
,
System.Threading
Threading
. , , , , .
, , VB, C# ,
Imports
/
using
, C# using , , using .
(Quantum Namespaces) ( ), ! VB , . ,
System
ComponentModel
System.Windows.Forms
ComponentModel
?
ComponentModel
. ,
ComponentModel.PropertyChangedEventArgs
, ( , ).
System.Windows.Forms
(, , , , ), (ambiguity errors).
VB2015 (Smart Name Resolution),
System
System.Windows.Forms
ComponentModel
, ,
System.ComponentModel
System.Windows.Forms.ComponentModel
, . , , , , . , , , ..
ComponentModel.PropertyChangedEventArgs
System.ComponentModel.PropertyChangedEventArgs
,
System.Windows.Forms.ComponentModel.PropertyChangedEventArgs
. , .
,
Windows
, ( ) ( ) ( ).
WinForms/WPF
UWP
.
53. Add
#33 , VB - , . , , — , :
Class Contact Property Name As String Property FavoriteFood As String End Class Module Program Sub Main() Dim contacts = New List(Of Contact) From { {"Leo", "Chocolate"}, {"Donnie", "Bananas"}, {"Raph", "The Blood of his Enemies"}, {"Mikey", "Pizza"} } End Sub <Runtime.CompilerServices.Extension> Sub Add(collection As ICollection(Of Contact), name As String, favoriteFood As String) collection.Add(New Contact With {.Name = name, .FavoriteFood = favoriteFood}) End Sub End Module
GitHubC# , Roslyn C#, . , (
, ), VS2015.
54. ,
, VB
Dim buffer(expression) As Byte
Dim buffer = New Byte(expression) {}
expression + 1
.
Microsoft BASIC,
DIM
( dimension — ). , , , : 0 expression. Microsoft BASIC 1 ( , 1984), ( ), 2002 .
, - , , VB , BASIC C , , C, C- . ,
buffer(10)
0 10, 9!
55. VB - , C#
, . , VB ( ) , — . :
CType({1, 2, 3}, Short())
CType(New Integer() {1, 2, 3}, Short ())
, Integer
Short
.CType({1, 2, 3}, Short())
New Short() {1, 2, 3}
. .
, , VB , C#. , :
Dim empty As Integer() = {}
:
Dim array As Predicate(Of Char)() = {AddressOf Char.IsUpper, AddressOf Char.IsLower, AddressOf Char.IsWhitespace}
( ):
Dim byteOrderMark As Byte() = {&HEF, &HBB, &HBF} '
.
,
IList(Of T)
,
IReadOnlyList(Of T)
,
ICollection(Of T)
,
IReadOnlyCollection(Of T)
IEnumerable(Of T)
, , ,
ParamArray IEnumerable
.
Pourquoi? , VB. , . 2008 VB C# «» {}, - ( , , ). , , , + , . .
56.
, LINQ. , .
, ,
.
57. CType, DirectCast C#
/ VB C#.
VB
CType
:
- ;
- ( );
- , ,
Long
Integer
(. «»); - (unboxes) ;
- ;
- (
CTypeDynamic
).
VB
DirectCast
:
- ;
- ;
- (
Integer Byte
); - ;
- ( );
- .
C# —
(Type)expression
:
CType
C# , . , . VB C# , IL .
, C#, , . .
,
CType
, (, ).
CType
,
DirectCast
, . , , IL :
Object
(
ValueType
) CLR «unbox» VB-, , (,
Short
Integer
). , , C#. . , .
Pourquoi? . , , , , .
58. «»
, ,
5 Mod 2 * 3
5 VB, «» C#
5 % 2 * 3
3.
, , . , (, (\) VB), , ,
.
!59. ; + & ; + VB <> + C#
, + () & () VB + C#.
String
:VB- “1” + 1 = 2.0
- “1” & 1 = “11”
C#, + &VB- “obj: “ + AppDomain.CurrentDomain ' Error: + not defined for String and AppDomain.
- ”obj: “ & AppDomain.CurrentDomain ' Error: & not defined for String and AppDomain.
- ”obj: “ + CObj(AppDomain.CurrentDomain) ' Exception, no + operator found.
- ”obj: “ & CObj(AppDomain.CurrentDomain) ' Exception, no & operator found.
C#- «obj: » + AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()
- «obj: » + (object)AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()
- «obj: » + (dynamic)AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()
:VBC#String Enum:VB- “Today: ” + DayOfWeek.Monday ' Exception: String «Today: » cannot be converted to Double.
- “Today: ” & DayOfWeek.Monday = “Today: 1”
- “Today: ” & DayOfWeek.Monday.ToString() = “Today: Monday”
C#- «Today: » + DayOfWeek.Monday == «Today: Monday»
: , + VB, - . + , , - . Pourquoi? :
- “10” — “1” = 9.0,
- “5” * “5” = 25.0,
- “1” << “3” = 8,
- “1” + 1 = 2.0,
- “1” + “1” = “11”
. — .
: +,
. , &, , (
, ). , , .
60. : 3 / 2 = 1,5
— :
« ?» . «». :
« . ?»VB C#.
C, , ,
« 5 9?» , \. , , , , 0 ( , -
INumeric
).
61. ^ Math.Pow
Math.Pow
. , . , (
custom
) ( ,
System.Numerics.BigInteger
).
: F# **, VB F# :
op_Exponent
op_Exponentiation
. F#
Pow
. . , .
62. =/<> /
C# '==' () , , ( ). VB . VB (
Is/IsNot
) .
: - Roslyn , . . . VB , = , C# , , , .
63. =/<> ( )
VB .
-, ( ) - ( ), ,
Option Compare Binary
Option Compare Text
.
Option Compare Binary
, , VS.
( ), ,
API. :
- /: “A” = “a”/“A” <> “a”
- : “A” > “a”
Select Case: Select Case “A” : Case “a”
:
Equals: “A”.Equals(“a”)
Contains: ”A”.Contains(“a”)
Distinct: From s In {“A”, “a”} Distinct
, , : VB . ,
Option Compare
, «Empty».
Module Program Sub Main() Dim s As String = Nothing If s = "" Then Console.WriteLine("Empty") End If End Sub End Module
GitHubs = "" VB —
String.IsNullOrEmpty(s)
.
, , , , , . , , .
Pourquoi? Option Compare Text
, , . , , .
, , , , .
, , . , . , , (collation) SQL Server, . , VB VB6, VBA Office, Excel Access, VBScript Windows, -, -… . , , .NET API , Option Compare Text, . , .NET API, .
null, , . VB6 .
String
"". , VB
String
. VB,
Left
Mid
,
String
. null .
Len(CStr(Nothing)) = 0
Left(CStr(Nothing)
,
5) = ""
,
CStr(Nothing).Length
CStr(Nothing).Trim()
.
,
?
. ( ).
:, , , . ! VB , ,
"String A" = "String B"
,
Microsoft.VisualBasic.CompilerServices.Operators.CompareString
, - , , . LINQ- . , VB ( ). , , - , . LINQ-to-SQL, LINQ-to-Entities , Microsoft. , VB , !
, C#, VB, LINQ . : 1) , VB , , 2) , VB , , LINQ-. , VB ().
: , « API».
Option Compare
VB,
InStr.Replace
Microsoft.VisualBasic.Strings
. , ?
, , , ? , , , : , , .
64. Nullable ( null )
VB C# - nullable. , (null-propagation).
SQL, , , null. , (, +), null, null.
"?."
:
obj?.Property obj
null, null, .
nullable , VB, C# . - : .
VB, nullable , null, null . 1 + null null null + null null. , (, = <>) C#:
- VB,
Is/IsNot
, Boolean?
- C# (==, !=, >, <, >=, <=)
bool
bool?
VB ( nullable ) null
null .
Boolean
=
Boolean?
,
True
,
False
null
.
. C#
non-nullable bool
,
.
,
. null. VB
NULL =
NULL —
NULL , TRUE.
, :

.
Null , , , C# .
. C# VB,
« null?» C#
(if (value == null))
. VB , VB (=/<>)
(Is/IsNot)
, VB
Is Nothing
non-nullable Boolean
.
, VB null, null.
And/AndAlso
Or/OrElse
.
Integer?
( ), VB, C# null, :
- 1 AND NULL NULL
- 1 OR NULL NULL
Boolean?
, VB .
- FALSE AND NULL FALSE
- TRUE OR NULL TRUE
- TRUE AND NULL NULL
- FALSE OR NULL NULL
,
True/False
, , null. ,
AndAlso
OrElse
.
C# (&&/||) (&/|)
nullable boolean (bool?)
. , , non-nullable boolean nullable boolean .
?VB , - :
Imports System.ComponentModel Class BindableRange Implements INotifyPropertyChanged Property _EndDate As Date? Property EndDate As Date? Get Return _EndDate End Get Set(value As Date?)
GitHub, , , , «EndDate change» . , ,
VB null ? ,
EndDate
, , ,
Nothing
.
VB :
«, , . » :
If value <> _EndDate Then _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End If
! . ,
non-nullable . ,
. , :
If value Is Nothing AndAlso _EndDate Is Nothing Then Return If value <> _EndDate Then Return
?, C# , VB. ( nullable , ), , null.
null —
«» « » . .
null « » «» . , , : comparer, , comparer . Roslyn,
Optional(Of T)
, , , null, , .
, NULL « », VB :
- , « , ?» « ».
- : « , ?» « ».
, ,
SQL- . , NULL SQL , NULL. . , , NULL . , . , , ( ). , , , , , NULL , SQL ( ).
VB.
nullable 2008 , VB ?LINQ to SQL
VB , , , , , , LINQ- . !
. SQL Server, ,
SET ANSI_NULLS OFF , SQL- C#,
WHERE Column = NULL
. , , OFF ( ). SQL Server ( ) . :
« ? . , - Option ANSI_NULLS Off VB.NET?» . :

, , , , , SQL Server, VB.
Quelque chose comme ça.
65. 1:1
, VB , , , . VB - , .
, , , , . VB , , , , , VB .
9.8.4 .
66. Function() a = b () => a = b
. ,
() => expression
C#
Function() expression
VB.
Function()
-, - , VB.
a = b
,
a
b
(
Boolean
),
b
. - (delegate relaxation) VB ( -) Sub- ( ). .
() => a = b
C# VB —
Sub() a = b
. — -
, .
=, , . (
Sub
-) , (
Function
-) .
67. Async Function
async void
C#
async
-, , ,
Task
void
, ,
Task
, .
VB.NET , ..
void Async
Async Sub
,
Task
Task(Of T)
—
Async Function
. , , VB, (relaxing)
Task Async
void
.
Async Sub
, , .
68. () VB
, VB:
Class Foo
GitHubVB,
C#. -,
Foo
Select
, ,
Where
.
Select
, ,
Select
,
Integer
. C# ,
.Where
(
Select
). , , .
LINQ API. , VB C#, . , C# , « », , , , . - , «» , , -.
, VB
, , C# , .
, Roslyn, :
« (range variables)?» « ?» . . , VB ,
Let
, C# — . , VB, C# 2012 , :
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CSharpExamples { struct Point { public int X { get { return 0; } } public int Y { get { return 0; } } } class Foo { public IEnumerable<Point> Select<T>(Func<string, T> selector) { return new Point[0]; } } static class Program { static void Main(string[] args) { var c = new Foo(); var q = from X in c let Y = "" select Y.CompareTo(-1); } } }
GitHub, — ? X, —
string
.
let
Y
, string. , Point,
X
Y
, ,
int
X
Y
, «» .
Y
select
,
int
int
`, … .
,
« ?» . VS2015 C# , «». , Roslyn C#, . , ( , ), - .
Pourquoi? , , , . , , VB C# .
69 70. As
From
cast
; 'As'
( , …)
From x As Integer In y
VB, ,
from int x in y
C#.
-, C# , ( ) .
.Cast<T>()
. VB , , , , .
-, ,
.Cast
( ). , , ,
.Cast
.Select
.
Pourquoi? . VB . ,
For Each x As T In collection
,
As T
.
From
As
For Each
( ,
As
).
71-75. Select
, ,
Par exemple:
From x In y Where x > 10
. , Select
.From x In y Select x Where x > 10
.From x In y Select x
, From x In y Select x = x
, x
— x
, x
— Select
. Select
.From x In y Select z = x.ToString()
, x
.From x In y Select x.FirstName
, From x In y Select FirstName = x.FirstName
.From x In y Select x.FirstName, x.LastName
— From x In y Select New With {x.FirstName, y.LastName}
, , . IEnumerable(Of $AnonymousType$)
, .
Pourquoi? (
Amanda Silver ). !
- ,
Select
, SQL , Select
, . LINQ VB Select , SQL, From . - , , .
- ,
Select
, SQL, - - . VB comma separated ( ) -. - ,
Select
, , , , , , , — .
? , , - , , :
Module Program Sub Main() Dim numbers = {1, 2, 3}
GitHubBC36606: Range variable name cannot match the name of a member of the 'Object' class
BC30978: Range variable '…' hides a variable in an enclosing block or a range variable previously defined in the query expression
— ,
Object
, , , , . (
n.ToString()
), . , .
76+.
. … … . … 20-25 (
— .. ).
Minute de publicité. 15-16 - .NET- DotNext 2019 Piter . , . , . .