Eine vollständige Liste der Unterschiede zwischen VB.NET und C #. Teil 2

Im ersten Teil des Artikels fand das Thema der Überlegenheit von VB.NET gegenüber C # in Bezug auf die TIOBE-Bewertung in den Kommentaren eine lebhafte Antwort. Schauen wir uns daher auf Anraten von AngReload die Trends von StackOverflow an.

C # ist immer noch stark! Die Revolution, über die beim letzten Mal so lange gesprochen wurde, wird abgesagt! Hurra, Genossen! Oder nicht? Die TIOBE-Bewertung basiert auf Suchmaschinenabfragen und die SO-Bewertung basiert auf Tags aus gestellten Fragen. Vielleicht wissen die Entwickler von VB.NET, zu denen viele Leute gehören, die keine Spezialitäten haben, einfach nichts über die Existenz von StackOverflow? Oder wenn Sie über Google oder sogar Bing dort angekommen sind, wissen Sie nicht, wie Sie eine Frage stellen sollen? Oder vielleicht haben sie genug Miscrosoft-Dokumentation und alle wenigen Fragen wurden bereits beantwortet.

Auf die eine oder andere Weise ist der Anteil von VB.NET spürbar und stabil, wenn auch nicht in erster Linie in Bezug auf das Volumen. Und natürlich wäre ein solches Ergebnis ohne ein starkes Team von Designern und Sprachentwicklern nicht möglich gewesen. Unten finden Sie den zweiten Teil der Übersetzung eines Artikels eines Mitglieds dieses Teams, Anthony Green .

Inhalt


Versteckter Text

Konvertierungen



Ausdrücke



Konvertierungen


34. Boolesche Transformationen


Das Konvertieren von Boolean True in einen vorzeichenbehafteten numerischen Typ ergibt -1 und in einen vorzeichenlosen Typ den Maximalwert für diesen Typ, während es in C # keine solchen Konvertierungen gibt. Die Convert.ToInt32 Methode konvertiert jedoch beispielsweise True in 1 , und so wird sie am häufigsten in IL . In der entgegengesetzten Richtung wird jede andere Zahl als 0 in True .

Warum? Der Grund, warum VB die Verwendung von -1 bis 1 bevorzugt, ist, dass die bitweise Negation von 0 (alle Bits werden auf 0 gesetzt) ​​in einer beliebigen Sprache -1 (alle Bits werden auf 1 ), sodass die Verwendung dieses Werts logisch und bitweise kombiniert Operationen wie And , Or und Xor .
Konvertierungen zu und von den Zeilen "True" und "False" werden ebenfalls unterstützt (natürlich ohne Berücksichtigung der Groß- und Kleinschreibung).

35. Konvertierungen zwischen Aufzählungstypen sowie zwischen Aufzählungstypen und ihren Basistypen sind völlig unbegrenzt, selbst wenn Option Strict auf Ein gesetzt ist


Aus philosophischer Sicht bezieht sich eine Sprache eher auf Enum als eine Menge benannter Konstanten eines grundlegenden Ganzzahltyps. Der Ort, an dem dies am offensichtlichsten ist, ist Gleichheit. Es ist immer zulässig, eine Ganzzahl mit einem Aufzählungswert zu vergleichen, während dies in C # einen Fehler ergibt.

Story Time: Die Roslyn-API wurde mehrfach intern überarbeitet. In jeder von ihnen wurde jedoch für jede Sprache eine SyntaxKind Aufzählung zugewiesen, die IfStatement , welche Syntax der Knoten darstellt (z. B. IfStatement , TryCastExpression ). Einmal verwendete ein Entwickler eine API, die versuchte, von der Sprache zu abstrahieren, und gab einen der SyntaxKind Werte zurück, jedoch nur als Integer . Ohne Fehler beim Vergleich von Raw Integer und SyntaxKind , kam dieser Entwickler sofort in mein Büro und beschwerte sich: „int is Implementierungsdetail, ich hätte gezwungen sein müssen, eine Besetzung zu machen! “ .

Im Laufe der Jahre haben wir bei der nächsten Überarbeitung der API die Eigenschaften ( Property Kind As SyntaxKind ), die auf einen sprachspezifischen Typ Property Kind As SyntaxKind , vollständig entfernt, und alle APIs haben begonnen, Integer . Der gesamte C # -Code war kaputt und der gesamte VB-Code funktionierte weiter, als wäre nichts passiert.

Wenig später beschlossen wir, diese Eigenschaft in RawKind und sprachspezifische Erweiterungsmethoden Kind() hinzuzufügen. Der gesamte C # -Code war fehlerhaft, da zum Aufrufen von Methoden Klammern erforderlich waren. Da sie jedoch in VB nicht benötigt wurden, funktionierte der gesamte VB-Code wieder, als wäre nichts passiert.

36. Die Prüfung auf Überlauf / negativen Überlauf für Ganzzahlarithmetik wird vollständig von der Kompilierungsumgebung (Projekteinstellungen) gesteuert, aber VB und C # verwenden unterschiedliche Standardwerte. In VB ist die Überlaufprüfung standardmäßig aktiviert


Integrale Typen haben einen Bereich, sodass Byte beispielsweise Werte von 0 bis 255 darstellen kann. Was passiert also, wenn Sie Byte 1 zu Byte 255 hinzufügen? Wenn die Überlauf- / Unterlaufprüfung deaktiviert ist, wird der Wert auf 0 SByte . Wenn der Typ signiert ist, wird auf die niedrigste negative Zahl SByte (z. B. -128 für SByte ). Dies weist höchstwahrscheinlich auf einen Fehler in Ihrem Programm hin. Wenn die Überlauf- / Unterlaufprüfung aktiviert ist, wird eine Ausnahme ausgelöst. Um zu verstehen, was ich meine, werfen Sie einen Blick auf diese harmlose For Schleife.

 Module Program Sub Main() For i As Byte = 0 To 255 Console.WriteLine(i) Next End Sub End Module 

Github-Quellcode

Standardmäßig löst diese Schleife eine Ausnahme in VB aus (da die letzte Iteration der Schleife über die Byte Grenze hinausgeht. Bei Byte Überlaufprüfung wird sie jedoch wiederholt, da i nach 255 wieder 0 wird.
Unterlauf ist die umgekehrte Situation, wenn das Subtrahieren unter den Minimalwert für den Typ den Maximalwert ergibt.

Eine häufigere Überlaufsituation ist einfach die Addition von zwei Zahlen. Nehmen Sie die Zahlen 130 und 150, beide als Byte . Wenn Sie sie zusammenfügen, lautet die Antwort 280, was nicht in Byte passt. Ihr Prozessor nimmt dies jedoch nicht wahr. Stattdessen berichtet er, dass die Antwort 24 ist.

Das hat übrigens nichts mit Conversions zu tun. Das Hinzufügen von zwei Bytes ergibt ein Byte; So funktioniert binäre Mathematik. Sie können jedoch auch einen Überlauf erhalten, indem Sie beispielsweise eine Konvertierung durchführen, wenn Sie versuchen, Long in Integer zu konvertieren. Ohne auf Überlauf zu prüfen, schneidet das Programm einfach die zusätzlichen Bits und Sachen so weit ab, wie es in diese Variable passt.

Was ist der Unterschied? Leistung. Das Überprüfen der CLR auf Überlauf erfordert im Vergleich zur Nichtprüfungsoption wie bei allen anderen Sicherheitsüberprüfungen etwas mehr Rechenzeit. VB basiert auf der Philosophie, dass Entwicklerproduktivität wichtiger ist als Rechenleistung. Daher ist die Sicherheitsüberprüfung standardmäßig aktiviert. Das heutige C # -Entwicklungsteam trifft möglicherweise eine andere Entscheidung über die Standardeinstellungen des Projekts. Angesichts der Tatsache, dass die ersten C # -Entwickler von C / C ++ - Entwicklern stammten, würde diese Gruppe wahrscheinlich verlangen, dass der Code nichts weiter tut, was Prozessorzyklen kosten könnte ;; Das ist ein schwieriger philosophischer Unterschied .

Nuance: Selbst wenn die Überlauf- / Unterlaufprüfung deaktiviert ist, NaN die Konvertierung von PositiveInfinity , NegativeInfinity und NaN von Single oder Double in Decimal eine Ausnahme aus, da keiner dieser Werte im Prinzip in Decimal dargestellt werden kann.

37. Beim Konvertieren von Gleitkommazahlen in ganzzahlige Typen werden Banker eher gerundet als abgeschnitten


Wenn Sie in VB 1,7 in eine Ganzzahl konvertieren, ist das Ergebnis 2. In C # ist das Ergebnis 1. Ich kann nichts über mathematische Regeln außerhalb Amerikas sagen, aber wenn ich von einer reellen Zahl zu einer Ganzzahl wechsle, runde ich instinktiv. Und keiner von denen, die ich außerhalb des Programmiererkreises kenne, glaubt, dass die nächste Ganzzahl zu 1,7 1 ist.

Es gibt tatsächlich mehrere Rundungsmethoden, und die in VB (und in der Math.Round-Methode) verwendete Rundungsart wird standardmäßig als Bankrundung oder Rundung von Statistikern bezeichnet. Sein Wesen ist, dass für eine Zahl in der Mitte zwischen zwei ganzen Zahlen VB auf die nächste gerade Zahl rundet. Also wird 1,5 auf 2 und 4,5 auf 4 gerundet. Was eigentlich nicht so funktioniert, wie wir es in der Schule gelernt haben - mir wurde beigebracht, von 0,5 aufzurunden (technisch gesehen von Null auf die Seite). Wie der Name schon sagt, hat die Bankrundung den Vorteil, dass Sie bei einer großen Anzahl von Berechnungen beim Runden in zwei Hälften teilen und nicht immer Geld ausgeben oder behalten. Mit anderen Worten, bei einem großen Satz begrenzt dies die Datenverzerrung auf die endgültige statistische Abweichung.

Woher kommt der Unterschied? Das Runden ist intuitiver und praktischer und wird schneller abgeschnitten. Wenn Sie die Verwendung von VB in LOB-Anwendungen in Betracht ziehen, insbesondere in Anwendungen wie Excel-Makros, die unter VBA ausgeführt werden, kann das einfache Löschen von Dezimalstellen ... Probleme verursachen.

Ich denke, es ist offensichtlich, dass die Konvertierungsmethode immer ein kontroverses Thema ist und explizit angegeben werden sollte, aber wenn Sie eine einzelne auswählen müssen ...

38. Es ist kein Fehler, NotInheritable-Klassen in / von Schnittstellen zu konvertieren, die sie zur Kompilierungszeit nicht implementieren


Wenn Sie eine nicht vererbbare Klasse auf eine Schnittstellenimplementierung prüfen, können Sie im Allgemeinen beim Kompilieren nachvollziehen, ob eine solche Konvertierung möglich ist, da Sie alle Schnittstellen dieses Typs und alle ihre Basistypen kennen. Wenn der Typ vererbt wird, können Sie nicht sicher sein, dass eine solche Konvertierung nicht möglich ist, da der Typ des referenzierten Laufzeitobjekts möglicherweise einen abgeleiteten Typ hat, der diese Schnittstelle implementiert. Es gibt jedoch eine Ausnahme aufgrund von COM-Interop, wenn zur Kompilierungszeit möglicherweise nicht sichtbar ist, dass der Typ etwas mit der Schnittstelle zu tun hat, dies jedoch zur Laufzeit der Fall ist. Aus diesem Grund generiert der VB-Compiler in solchen Fällen eine Warnung.

Warum? VB und COM sind zusammen aufgewachsen, als sie Kinder in der alten Nachbarschaft waren. Daher gibt es im Sprachdesign mehrere Lösungen, bei denen VB den Dingen große Aufmerksamkeit schenkt, die zum Zeitpunkt der Veröffentlichung von .NET 1.0 nur in COM vorhanden waren.

39. Der Versuch, null in einen aussagekräftigen Typ zu entpacken (zu entpacken), führt zu einem Standardwert des Typs und nicht zu einer NullReferenceException


Ich glaube, dass dies technisch auch für Referenztypen gilt, aber ja:
 CInt(CObj(Nothing)) = 0 

Warum? Weil CInt(Nothing) = 0 ist und die Sprache tendenziell etwas konsistent ist, unabhängig davon, ob Sie Ihre Variablen eingegeben haben oder nicht. Dies gilt für jede Struktur, nicht nur für integrierte sinnvolle Typen. Weitere Informationen finden Sie in der Begründung unter Nr. 25 .

40. Unboxing unterstützt primitive Typkonvertierungen


Sowohl in VB als auch in C # können Sie Short in Integer konvertieren. Was ist jedoch, wenn Sie versuchen, gepackte Short in Integer zu konvertieren? In VB wird Short zuerst entpackt und dann in Integer konvertiert. In C # wird eine InvalidCastException ausgelöst, es sei denn, Sie entpacken kurz vor der Konvertierung in int manuell.
Dies gilt für alle internen Konvertierungen, d. H. Gepackte numerische Typen, Konvertierungen zwischen Zeichenfolgen und numerischen Typen, Zeichenfolgen und Datumsangaben (ja, Dezimal und Datum sind primitive Typen).

Warum? Um ein konsistentes Verhalten sicherzustellen, unabhängig davon, ob Ihr Programm vollständig eingegeben, als Objekt eingegeben oder von einer Option zur anderen überarbeitet wurde. Siehe Nr. 39 oben.

41. Es gibt Konvertierungen zwischen String und Char


  • String in Char konvertiert und repräsentiert sein erstes Zeichen.
  • Char auf String einzig vernünftige Weise in String konvertiert.

Weil sich niemand außer mir an die Syntax eines Zeichenliteral in VB erinnert (und es sollte nicht).

42. Es gibt Konvertierungen zwischen String und Char Array


  • String in ein Char Array konvertiert, das aus allen Zeichen besteht.
  • Das Char Array wird in einen String konvertiert, der aus allen seinen Elementen besteht.

Für die Bestimmtheit: Diese Transformationen erstellen neue Objekte, Sie erhalten keinen Zugriff auf die interne String Struktur.

Witzige Geschichte: Ich habe einmal eine Änderung zwischen .NET 3.5 und 4.0 gefunden (oder vielleicht gemeldet und recherchiert), weil das .NET-Team zwischen diesen Versionen den ParamArray Modifikator zum zweiten String.Join Überladungsparameter hinzugefügt hat, der ein Array von Zeichenfolgen enthält . Die genauen Annahmen gehen mit der Zeit verloren (wahrscheinlich zum Besseren), aber meiner Meinung nach liegt der Grund darin, dass Sie mit dem Modifikator ParamArray jetzt ein Char Array in eine Zeichenfolge konvertieren und als separates Element an das Parameter-Array übergeben können. Lustiges Thema.

43 und 44. Konvertierungen von Zeichenfolgen in numerische Typen und Datumsangaben unterstützen (normalerweise) die Literalsyntax.


  • CInt("&HFF") = 255
  • CInt("1e6") = 1_000_000
  • CDate("#12/31/1999#") = #12/31/1999#

Dies funktioniert mit Basispräfixen und ermöglicht die bequeme Konvertierung hexadezimaler (oder oktaler) Eingaben in eine Zahl: CInt("&H" & input) . Leider verschlechtert sich diese Symmetrie zum Zeitpunkt dieses Schreibens, da die VB-Laufzeit nicht aktualisiert wurde, um das binäre Präfix & B oder das 1_000 stellige Gruppentrennzeichen zu unterstützen, aber ich hoffe, dass dies in der nächsten Version behoben wird. Die wissenschaftliche Notation funktioniert, jedoch ohne CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM# unterstützen auch Standard-Datumsformate. CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM# funktioniert das in ISO-8601 verwendete JSON-Format auch: CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM# .

Warum? Ich kenne keinen anderen Grund als Bequemlichkeit. Aber ich möchte wirklich Unterstützung für andere gängige Formate anbieten, die heute im Netzwerk fast allgegenwärtig sind, wie #FF, U + FF, 0xFF. Ich denke, dies könnte das Leben in einigen Arten von Anwendungen erheblich erleichtern ...

45. KEINE Konvertierungen zwischen Char und Integer-Typen


WAS?!?!?
Sind Sie überrascht, nachdem Sie über all diese zusätzlichen Transformationen gelesen haben? VB verbietet Konvertierungen zwischen Char und Integer :

  • CInt("A"c) wird nicht kompiliert.
  • CChar(1) wird nicht kompiliert.

Warum? Es ist nicht klar, was passieren wird. Normalerweise verwendet VB in solchen Situationen einen pragmatischen und / oder intuitiven Ansatz, aber um CInt("1") auszudrücken CInt("1") würde die Hälfte der Leser die Nummer 1 ( CInt("1") 1) und die Hälfte die Nummer 49 (ASCII / UTF-Code für) erwarten Zeichen 1). Anstatt in der Hälfte der Fälle die falsche Wahl zu ChrW verfügt VB über spezielle Funktionen zum Konvertieren von Zeichen in ASCII / Unicode-Codes und umgekehrt, AscW bzw. ChrW .

Ausdrücke


46. ​​Nichts <> null


Das Literal Nothing in VB bedeutet nicht null . Dies bedeutet "der Standardwert für den Typ, für den es verwendet wird", und es kommt nur so vor, dass für Referenztypen der Standardwert null ist. Der Unterschied ist nur wichtig, wenn er in einem Kontext verwendet wird, in dem:

  1. Nichts nimmt einen bedeutenden Typ an und ...
  2. Aus dem Zusammenhang ist nicht ersichtlich, dass er dies tut.

Schauen wir uns einige Beispiele an, die veranschaulichen, was dies bedeutet.

Das erste, vielleicht ein bisschen seltsam, aber ich glaube nicht, dass die meisten Leute von dem Verständnis, dass dieses Programm "True" drucken wird, in die Luft gesprengt werden:

 Module Program Sub Main() Dim i As Integer = 0 If i = Nothing Then Console.WriteLine("True") End If End Sub End Module 

Github-Quellcode

Der Grund ist ganz einfach: Sie vergleichen Integer (0) mit dem Standardwert seines Typs (auch 0). Das Problem tritt in VB2005 / 2008 auf, wenn Sie nullfähige sinnvolle Typen hinzufügen. Schauen Sie sich dieses Beispiel an:

  Module Program Sub Main() Dim i = If(False, 1, Nothing) End Sub End Module 

Github-Quellcode

Wie kann jemand vorschlagen, dass Typ i eine Integer? ( Nullable(Of Integer) ). Dies ist jedoch nicht der Fall, da Nothing den Typ aus dem Kontext erhält und der einzige Typ in diesem Kontext vom zweiten Operanden stammt. Dies ist eine einfache non-nullable Integer (technisch gesehen hat Nothing nie einen Typ). Eine andere Möglichkeit, dieses Problem zu betrachten, ist das folgende Beispiel:

 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 

Github-Quellcode

Auch hier scheint es intuitiv, dass Nothing einen "nullbaren" Hinweis hinzufügt und dass die Sprache eine Überladung auswählt, die nullable akzeptiert, dies jedoch nicht (wählt non-nullable , da es "am spezifischsten" ist). Zumindest kann davon ausgegangen werden, dass der Nothing Ausdruck wie null in C # überhaupt nicht für Integer gilt und dass die nullfähige Überladung von der Ausnahmemethode ausgewählt wird. Dies basiert jedoch wiederum auf der falschen Vorstellung, dass Nothing = null (Is null?) .

Nuance: In C # 7.1 wurde ein neuer default hinzugefügt, der mit Nothing in VB übereinstimmt. Wenn Sie alle drei obigen Beispiele in C # mit default anstelle von null neu schreiben, erhalten Sie genau das gleiche Verhalten .

Was kann man dagegen tun? Es gibt mehrere Vorschläge, aber noch keiner hat gewonnen:

  • Zeigen Sie jedes Mal eine Warnung an, wenn Nothing in einen aussagekräftigen Typ konvertiert wird und in einem nullable signifikanten Typ nicht null .
  • Erweitern Sie Nothing auf 0 , 0.0 , ChrW(0) , False , #1/1/0001 12:00:00 AM# ChrW(0) #1/1/0001 12:00:00 AM# oder New T (der Standardwert für jede Struktur) jedes Mal, wenn der Wert zur Laufzeit einer von ist oben aufgeführt.
  • Fügen Sie eine neue Syntax hinzu, die "Null, nein, wirklich!" Null Wie Null oder Nothing?
  • Fügen Sie eine neue Syntax in Form eines Suffixes (?) Hinzu, das den Wert in nullable umschließt, um den Typ abzuleiten, z. B. If(False, 0?, Nothing)
  • Fügen Sie nullfähige Konvertierungsoperatoren für integrierte Typen hinzu, um Hinweise zur Typinferenz zu vereinfachen, z. B. If (False, CInt? (0), Nothing)

Ich würde gerne Ihre Gedanken in den Kommentaren und / oder auf Twitter hören .

Um es zusammenzufassen:

  • Früher - VB6 und VBA haben "Nothing", "Null", "Empty" und "Missing", was verschiedene Dinge bedeutet.
  • 2002 - In VB.NET gibt es nur Nothing (der Standardwert in einem bestimmten Kontext) und in C # nur null .
  • 2005 - C # fügt default(T) (ein Standardwert vom Typ T ), da neu hinzugefügte Generika eine Situation schaffen, in der Sie einen Wert initialisieren müssen, aber nicht wissen, ob es sich um einen Referenztyp oder einen signifikanten Wert handelt. VB unternimmt nichts, da dieses Skript bereits von Nothing geschlossen wird.
  • 2017 - C # fügt default hinzu ( default im Kontext), da es viele Szenarien gibt, in denen die Angabe von T redundant oder unmöglich ist

VB widersetzt sich weiterhin dem Hinzufügen eines Null Ausdrucks (oder eines Äquivalents), weil:

  • Die Syntax wird die Änderung unterbrechen.
  • Die Syntax wird die Änderung nicht unterbrechen, aber je nach Kontext unterschiedliche Bedeutungen haben.
  • Die Syntax ist zu unauffällig (z. B. Nothing? ). Stellen Sie sich vor, Sie müssen laut über Nothing und Nothing? sprechen Nothing? einer Person etwas erklären.
  • Die Syntax ist möglicherweise zu hässlich (z. B. Nothing? ).
  • Das Nullausdrucksskript wird bereits von Nothing geschlossen, und diese Funktion ist die meiste Zeit vollständig redundant.
  • Überall sollten alle Dokumentationen und Anweisungen aktualisiert werden, um die Verwendung einer neuen Syntax zu empfehlen, die für die meisten Szenarien grundsätzlich Nothing für veraltet erklärt.
  • Nothing und Null verhalten sich zur Laufzeit in Bezug auf späte Bindung, Transformationen usw. immer noch gleich.
  • Es kann wie eine Waffe in einem Stich sein.

Irgendwie so.

Offtopic (aber verwandt)

Hier ist ein Beispiel, das dem zweiten oben sehr ähnlich ist, jedoch ohne Typinferenz:

 Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) End Sub End Module 

Github-Quellcode

Dieses Programm zeigt 0 an. Es verhält sich aus demselben Grund genauso wie das zweite Beispiel, zeigt jedoch ein separates, wenn auch verwandtes Problem. Was ist Dim i as Integer? = If(False, 1, Nothing) intuitiv Dim i as Integer? = If(False, 1, Nothing) Dim i as Integer? = If(False, 1, Nothing) sich genauso verhält wie Dim i As Integer? : If False Then i = 1 Else i = Nothing Dim i As Integer? : If False Then i = 1 Else i = Nothing . In diesem Fall ist dies nicht der Fall, da der bedingte Ausdruck (If) keine Informationen des endgültigen Typs an seine Operanden weiterleitet. Es stellt sich heraus, dass dadurch alle Ausdrücke in VB aufgeschlüsselt werden, die auf der so genannten endgültigen (kontextuellen) Typisierung ( Nothing , AddressOf , ein Array von Literalen, Lambda-Ausdrücken und interpolierten Zeichenfolgen) AddressOf laut Ausnahmen werfen. Hier ist ein Beispiel für eine nicht kompilierte Option:

 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 

Github-Quellcode

Dieses Programm wird nicht kompiliert. Stattdessen meldet es einen Fehler im If Ausdruck, der den Ausdruckstyp nicht bestimmen kann, wenn beide AddressOf Ausdrücke AddressOf Func(Of Integer, Integer, Integer) Delegaten Func(Of Integer, Integer, Integer) empfangen 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 .

Warum? 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() .

Warum? , '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# , , .

Warum? , , 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 .

Warum? , 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#. . , .

Warum? . , , , , .

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, - . + , , - . Warum? :

  • “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) .
, , , , , . , , .

Warum? 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.
Irgendwie so.

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#, . , ( , ), - .

Warum? , , , . , , 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 .

Warum? . VB . , For Each x As T In collection , As T . From As For Each ( , As ).

71-75. Select , ,


Zum Beispiel:

  • 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$) , .

Warum? ( 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 der Werbung. 15-16 - .NET- DotNext 2019 Piter . , . , . .

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


All Articles