Une liste exhaustive des différences entre VB.NET et C #. 2e partie

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


Texte masqué

Conversions



Expressions



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 github

Par 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:

  1. Rien ne prend un type significatif, et ...
  2. 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 github

La 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 github

Compris, 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 github

Ici 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 github

Ce 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 github

Ce 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 

GitHub

C# «-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.ioBoundParenthesized 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 

GitHub

C# ( 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 

GitHub

C# , 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#

  • «1» + 1 == «11»

, + &
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()

:
VB

  • 1 + 1 = 2
  • 1 & 1 = “11”

C#

  • 1 + 1 == 2

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 

GitHub

s = "" 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 = NULLNULL , 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?) ' This line here: If value = _EndDate Then Return _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End Set End Property Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged End Class Module Program WithEvents Range As New BindableRange Sub Main() Range.EndDate = Today Range.EndDate = Today Range.EndDate = Nothing Range.EndDate = Nothing End Sub Private Sub BindableRange_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles Range.PropertyChanged Console.WriteLine(e.PropertyName & " changed.") End Sub End Module 

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 'Function [Select](Of T)(selector As Func(Of String, T)) As Foo ' Return Me 'End Function Function Where(predicate As Func(Of String, Boolean)) As Integer Return 0 End Function End Class Module Program Sub Main() Dim c As New Foo Dim q = From x In c Where True Select x End Sub End Module 

GitHub

VB, 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 , xx , xSelect . 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.LastNameFrom 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} ' BC36606: Range variable name cannot match the name of a member of the 'Object' class. Dim q = From n In numbers Select n.ToString() End Sub End Module 

GitHub

BC36606: 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 . , . , . .

Source: https://habr.com/ru/post/fr445580/


All Articles