En la 
primera parte del artículo, el tema de la superioridad de VB.NET sobre C # en términos de calificación TIOBE encontró una respuesta animada en los comentarios. Por lo tanto, 
siguiendo los 
consejos de AngReload, veamos las 
tendencias de StackOverflow.

C # sigue siendo fuerte! ¡La revolución de la que se habló tanto tiempo la última vez se cancela! ¡Hurra, camaradas! O no? La calificación TIOBE se basa en las consultas de los motores de búsqueda, y la calificación SO se basa en las etiquetas de las preguntas formuladas. ¿Quizás los desarrolladores de VB.NET, que incluyen a muchas personas que no tienen especialidades, simplemente no conocen la existencia de StackOverflow? ¿O habiendo llegado allí a través de Google, o incluso Bing, no entiendo cómo hacer una pregunta? O tal vez tienen suficiente documentación de Miscrosoft, y todas las pocas preguntas ya han sido respondidas.
De una forma u otra, la participación de VB.NET es notable y estable, aunque no en primer lugar en términos de volumen. Y, por supuesto, tal resultado no hubiera sido posible sin un equipo fuerte de diseñadores y desarrolladores de idiomas. A continuación se muestra la segunda parte de la traducción de un artículo de un miembro de este equipo, 
Anthony Green .
Contenido
Conversiones
34. transformaciones booleanas
La conversión de 
Boolean True a cualquier tipo numérico con signo produce 
-1 , y a cualquier tipo sin signo proporciona el valor máximo para este tipo, mientras que en C # no hay tales conversiones. Sin embargo, el método 
Convert.ToInt32 , por ejemplo, convierte 
True en 
1 , y así es como se representa con mayor frecuencia en 
IL . En la dirección opuesta, cualquier número que no sea 
0 se convierte en 
True .
Por qué La razón por la que VB prefiere usar de 
-1 a 
1 es porque la negación a nivel de bits de 0 (todos los bits se establecen en 0) en cualquier idioma es 
-1 (todos los bits se establecen a 
1 ), por lo que el uso de este valor combina lógica y bit a bit operaciones como 
And , 
Or y 
Xor .
Las conversiones hacia y desde las líneas "Verdadero" y "Falso" también son compatibles (por supuesto, sin distinción entre mayúsculas y minúsculas).
35. Las conversiones entre los tipos Enum, así como entre los tipos Enum y sus tipos base son completamente ilimitadas, incluso si Option Strict está configurado en On
Desde un punto de vista filosófico, un lenguaje se refiere a los tipos 
Enum más bien como un conjunto de constantes con nombre de un tipo entero básico. El lugar donde esto es más obvio es la igualdad. Siempre está permitido comparar cualquier número entero con un valor de enumeración, mientras que en C # esto da un error.
Hora del cuento: La API de Roslyn ha pasado por muchas revisiones internas. Pero en cada uno de ellos, se 
SyntaxKind una enumeración 
SyntaxKind para cada idioma, que le indica qué sintaxis representa el nodo (por ejemplo, 
IfStatement , 
TryCastExpression ). Una vez, un desarrollador usó una API que trató de abstraer del lenguaje y devolvió uno de los valores de 
SyntaxKind , pero solo como 
Integer , y sin recibir errores al comparar 
Integer y 
SyntaxKind , este desarrollador vino inmediatamente a mi oficina y se quejó: 
"int is detalle de implementación, ¡debería haberme obligado a hacer un reparto! " .
Con los años, durante la próxima revisión de la API, eliminamos por completo las propiedades ( 
Property Kind As SyntaxKind ), que apuntaban a un tipo específico de idioma, y todas las API comenzaron a devolver 
Integer . Todo el código C # se rompió y todo el código VB continuó funcionando como si nada hubiera pasado.
Un poco más tarde, decidimos cambiar el nombre de esta propiedad a 
RawKind y agregar métodos de extensión específicos del idioma 
Kind() . Todo el código C # se rompió porque se necesitaban paréntesis para llamar a los métodos, pero como no se necesitaban en VB, todo el código de VB continuó funcionando nuevamente como si nada hubiera pasado.
36. La comprobación de desbordamiento / desbordamiento negativo para aritmética de enteros está completamente controlada por el entorno de compilación (configuración del proyecto), pero VB y C # utilizan diferentes valores predeterminados; en VB, la comprobación de desbordamiento está habilitada de forma predeterminada
Los tipos integrales tienen un rango, entonces, por ejemplo, 
Byte puede representar valores de 0 a 255. Entonces, ¿qué sucede cuando agrega 
Byte 1 a 
Byte 255? Si la comprobación de desbordamiento / desbordamiento está desactivada, el valor se desplaza a 0. Si el tipo está firmado, se desplaza al número negativo más bajo (por ejemplo, -128 para 
SByte ). Esto probablemente indica un error en su programa. Si la comprobación de desbordamiento / desbordamiento está habilitada, se genera una excepción. Para entender lo que quiero decir, eche un vistazo a este inofensivo bucle 
For .
 Module Program Sub Main() For i As Byte = 0 To 255 Console.WriteLine(i) Next End Sub End Module 
código fuente de githubPor defecto, este bucle generará una excepción en VB (ya que la última iteración del bucle va más allá del borde de 
Byte . Pero con la comprobación de desbordamiento desactivada, se repite porque después de 255 vuelvo a 0 nuevamente.
Underflow es la situación opuesta cuando se resta por debajo del valor mínimo para los resultados de tipo en el valor máximo.
Una situación de desbordamiento más común es simplemente la suma de dos números. Tome los números 130 y 150, ambos como 
Byte . Si los junta, la respuesta es 280, que no cabe en Byte. Pero su procesador no lo percibe. En cambio, informa que la respuesta es 24.
Por cierto, esto no tiene nada que ver con las conversiones. Agregar dos bytes da un byte; Así es como funciona la matemática binaria. Aunque también puede obtener un desbordamiento realizando una conversión, por ejemplo, al intentar convertir Long a Integer. Sin verificar el desbordamiento, el programa simplemente corta los bits y cosas adicionales tanto como cabe en esta variable.
Cual es la diferencia Rendimiento La comprobación del desbordamiento del CLR requiere un poco más de tiempo de cálculo en comparación con la opción de no comprobación, como todas las demás comprobaciones de seguridad. VB se basa en la filosofía de que la productividad del desarrollador es más importante que el rendimiento computacional, por lo que, de forma predeterminada, tiene habilitada la comprobación de seguridad. El equipo de desarrollo de C # de 
hoy puede tomar una decisión diferente sobre la configuración predeterminada del proyecto, pero teniendo en cuenta que los primeros desarrolladores de C # provienen de desarrolladores de C / C ++, este grupo de personas probablemente requerirá que el código no haga nada más, lo que podría costar ciclos de procesador ; 
Esta es una diferencia filosófica difícil .
Matiz: incluso si la verificación de desbordamiento / subflujo está desactivada, la conversión de los 
NaN PositiveInfinity , 
NegativeInfinity , 
NaN de 
Single o 
Double to 
Decimal arrojará una excepción, ya que ninguno de estos valores puede representarse en decimal.
37. La conversión de números de coma flotante a tipos enteros utiliza el redondeo de los banqueros en lugar de truncar
Si convierte 1.7 a un número entero en VB, el resultado será 2. En C #, el resultado será 1. No puedo decir nada sobre reglas matemáticas fuera de Estados Unidos, pero cuando cambio de un número real a un número entero, redondeo instintivamente. Y ninguno de los que conozco fuera del círculo de programadores cree que el número entero más cercano a 1.7 es 1.
En realidad, existen varios métodos de redondeo, y el tipo de redondeo utilizado en VB (y en el método Math.Round) se denomina redondeo bancario o redondeo de las estadísticas por defecto. Su esencia es que para un número en el medio entre dos enteros, VB se redondea al número par más cercano. Entonces 1.5 se redondea a 2, y 4.5 se redondea a 4. Lo que en realidad no funciona como nos enseñaron en la escuela: me enseñaron a redondear desde 0.5 (técnicamente, redondear al lado desde cero). Pero, como su nombre lo indica, el redondeo bancario tiene la ventaja de que, con una gran cantidad de cálculos, se divide al redondear a la mitad y no siempre cede ni guarda dinero. En otras palabras, en un conjunto grande, esto limita la distorsión de datos a la desviación estadística final.
¿De dónde viene la diferencia? El redondeo es más intuitivo y práctico, truncando más rápido. Si considera usar VB en aplicaciones LOB, y especialmente en aplicaciones como macros de Excel que se ejecutan en VBA, simplemente dejar caer decimales puede causar ... problemas.
Creo que es obvio que el método de conversión es siempre un tema controvertido y debe indicarse explícitamente, pero si necesita elegir uno solo ...
38. No es un error convertir clases NotInheritable a / desde interfaces que no implementan en tiempo de compilación
En términos generales, si está verificando una clase No heredable para una implementación de interfaz, puede comprender en el momento de la compilación si dicha conversión es posible porque conoce todas las interfaces de este tipo y todos sus tipos básicos. Si el tipo se hereda, no puede estar seguro de que tal conversión sea imposible, porque el tipo del objeto de tiempo de ejecución al que se hace referencia puede tener un tipo más derivado que implemente esta interfaz. Sin embargo, hay una excepción debido a la interoperabilidad COM, cuando en el momento de la compilación puede no ser visible que el tipo tiene algo que ver con la interfaz, pero en tiempo de ejecución lo hará. Por esta razón, el compilador de VB genera una advertencia en tales casos.
Por qué VB y COM crecieron juntos cuando eran niños en el antiguo barrio. Por lo tanto, hay varias soluciones en diseño de lenguaje en las que VB presta gran atención a las cosas que existían solo en COM en el momento del lanzamiento de .NET 1.0.
39. Intentar descomprimir (unbox) nulo en un tipo significativo da como resultado un valor predeterminado del tipo, no una NullReferenceException
Creo que técnicamente esto también es cierto para los tipos de referencia, pero sí:
 CInt(CObj(Nothing)) = 0 
Por qué Porque 
CInt(Nothing) = 0 , y el lenguaje tiende a ser algo consistente, independientemente de si escribió sus variables o no. Esto se aplica a cualquier estructura, no solo a los tipos significativos incorporados. Consulte la 
justificación en el n. ° 25 para obtener más detalles.
40. Unboxing admite conversiones de tipo primitivo
Tanto en VB como en C # puede convertir 
Short a 
Integer , pero ¿qué 
Integer si intenta convertir 
Short a 
Integer empaquetado? En VB 
Short se desempaquetará primero y luego se convertirá a 
Integer . En C #, a menos que desempaquete manualmente antes de convertir a 
int , se generará una 
InvalidCastException .
Esto se aplica a todas las conversiones internas, es decir, tipos numéricos empaquetados, conversiones entre cadenas y tipos numéricos, cadenas y fechas (sí, Decimal y Fecha son tipos primitivos).
Por qué Una vez más, para garantizar un comportamiento coherente, ya sea que su programa esté completamente escrito, escrito como Objeto o refactorizado de una opción a otra. Ver 
# 39 arriba.
41. Hay conversiones entre String y Char
- Stringconvierte en- Char, que representa su primer carácter.
- Charconvierte en- Stringúnica forma razonable.
Porque nadie excepto yo recuerda la sintaxis de un carácter literal en VB (y no debería).
42. Hay conversiones entre String y Char array
- Stringconvierte en una matriz- Charconsta de todos sus caracteres.
- La matriz Charse convierte en unaStringconsta de todos sus elementos.
Para mayor claridad: estas transformaciones crean nuevos objetos, no tiene acceso a la estructura interna de 
String .
Historia divertida: una vez encontré (o tal vez lo informé, y estaba investigando) romper el cambio entre .NET 3.5 y 4.0, porque entre estas versiones el equipo .NET agregó el modificador 
ParamArray al segundo 
String.Join sobrecarga 
String.Join , que toma una serie de cadenas . Las suposiciones exactas se pierden en el tiempo (probablemente para mejor), pero, como creo, la razón es que con el modificador 
ParamArray ahora puede convertir una matriz 
Char en una cadena y pasarla como un elemento separado a la matriz de parámetros. Tema divertido
43 y 44. Las conversiones de cadenas a tipos numéricos y de fecha admiten sintaxis literal (normalmente)
- CInt("&HFF") = 255
- CInt("1e6") = 1_000_000
- CDate("#12/31/1999#") = #12/31/1999#
Esto funciona con prefijos básicos y permite utilizar una forma muy conveniente de convertir la entrada hexadecimal (u octal) en un número: 
CInt("&H" & input) . Desafortunadamente, esta simetría se está degradando en el momento de escribir esto, porque el tiempo de ejecución de VB no se ha actualizado para admitir el prefijo binario & B o el 
1_000 grupo de 
1_000 dígitos, pero espero que esto se solucione en la próxima versión. La notación científica funciona, pero sin sufijos de tipo, y las conversiones de fecha también admiten formatos de fecha estándar, por lo que el formato JSON utilizado en ISO-8601 también funciona: 
CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM#Por qué No conozco otra razón que la conveniencia. Pero 
realmente me gustaría ofrecer soporte para otros formatos comunes que son casi omnipresentes en la red hoy en día, como #FF, U + FF, 0xFF. Creo que esto podría facilitar enormemente la vida en algunos tipos de aplicaciones ...
45. NO conversiones entre los tipos Char y enteros
¿Qué?!?!?Después de leer sobre todas estas transformaciones adicionales, ¿estás sorprendido? VB prohíbe las conversiones entre 
Char e 
Integer :
- CInt("A"c)no se compila.
- CChar(1)no compila.
Por qué No está claro qué va a suceder. Por lo general, VB en tales situaciones utiliza un enfoque pragmático y / o intuitivo, pero para la expresión 
CInt("1") creo que la mitad de los lectores esperaría el número 1 (valor de carácter 1), y la otra mitad esperaría el número 49 (código ASCII / UTF para personaje 1). En lugar de tomar la decisión incorrecta en la mitad de los casos, VB tiene funciones especiales para convertir caracteres a códigos ASCII / Unicode y viceversa, 
AscW y 
ChrW respectivamente.
Expresiones
46. Nada <> nulo
El literal 
Nothing en VB no significa 
nulo . Significa 
"el valor predeterminado para el tipo para el que se usa", y resulta que para los tipos de referencia, el valor predeterminado es nulo. La diferencia solo importa cuando se usa en un contexto en el que:
- Nada adquiere un tipo significativo, y ...
- No está claro por el contexto que él está haciendo esto.
Veamos algunos ejemplos que ilustran lo que esto significa.
El primero, quizás un poco extraño, pero no creo que la mayoría de la gente se sorprenda al comprender que este programa imprimirá "Verdadero":
 Module Program Sub Main() Dim i As Integer = 0 If i = Nothing Then Console.WriteLine("True") End If End Sub End Module 
código fuente de githubLa razón es bastante simple: está comparando 
Integer (0) con el valor predeterminado de su tipo (también 0). El problema ocurre en VB2005 / 2008 cuando agrega tipos significativos anulables. Echa un vistazo a este ejemplo:
  Module Program Sub Main() Dim i = If(False, 1, Nothing) End Sub End Module 
código fuente de githubEntendido, ¿cómo puede alguien sugerir que el tipo 
i es un número 
Integer? ( 
Nullable(Of Integer) ). Pero esto no es así, porque 
Nothing obtiene el tipo del contexto, y el único tipo en este contexto proviene del segundo operando, y este es un 
non-nullable Integer simple 
non-nullable Integer (técnicamente, 
Nothing nunca tiene un tipo). Otra forma de ver este problema es con el siguiente ejemplo:
 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 
código fuente de githubNuevamente, aquí, intuitivamente, parece que 
Nothing agrega una pista "anulable" y que el idioma selecciona una sobrecarga que acepta 
nullable , pero no lo hace (selecciona 
non-nullable , porque es "más específico"). Como mínimo, se puede suponer que, como nulo en C #, la expresión 
Nothing no se aplica a 
Integer , y que la sobrecarga nulable se seleccionará mediante el método de excepción, pero esto se basa nuevamente en la idea incorrecta de que 
Nothing = null (Is null?) .
Matiz: se ha agregado una nueva expresión 
default en C # 7.1 que no coincide con 
Nothing en VB. Si reescribe los tres ejemplos anteriores en C # usando el 
default lugar de 
null , 
obtendrá exactamente el mismo comportamiento .
¿Qué se puede hacer al respecto? Hay varias sugerencias, pero ninguna ha ganado aún:
- Mostrar una advertencia cada vez que Nothingconvierte en un tipo significativo y no esnullen un tipo significativonullable.
- Expanda maravillosamente Nothinga0,0.0,ChrW(0),False,#1/1/0001 12:00:00 AM#ChrW(0)#1/1/0001 12:00:00 AM#oNew T(el valor predeterminado para cualquier estructura) cada vez que su valor en tiempo de ejecución sea uno de enumerados arriba.
- Agregue una nueva sintaxis que significa "Nulo, no, en serio" ¿Como NulloNothing?
- Agregue una nueva sintaxis en forma de sufijo (?) Que envuelve el valor en nulable para ayudar a deducir el tipo, por ejemplo If(False, 0?, Nothing)
- Agregue operadores de conversión anulables para los tipos integrados para que sea más fácil dar pistas para la salida de tipo, por ejemplo, If (False, CInt? (0), Nothing)
Me gustaría escuchar tu opinión en los comentarios y / o 
en Twitter .
Para resumir:
- Tiempos anteriores: VB6 y VBA tienen "Nothing", "Null", "Empty" y "Missing", lo que significa cosas diferentes.
- 2002: en VB.NET solo hay Nothing(el valor predeterminado en un contexto específico) y en C #, solonull.
- 2005: C # agrega el default(T)(un valor predeterminado del tipoT), porque los genéricos recién agregados crean una situación en la que necesita inicializar un valor, pero no sabe si es un tipo de referencia o significativo; VB no hace nada porque este script ya está cerrado porNothing.
- 2017: C # agrega el default(valordefaulten contexto) ya que hay muchos escenarios en los que especificarTredundante o imposible
VB continúa resistiéndose a agregar una expresión 
Null (o equivalente) porque:
- La sintaxis romperá el cambio.
- La sintaxis no romperá el cambio, pero dependiendo del contexto significará cosas diferentes.
- La sintaxis será demasiado discreta (por ejemplo, Nothing?); ¿Imagina que necesitas hablar en voz alta sobreNothingandNothing?para explicarle algo a una persona.
- La sintaxis puede ser demasiado fea (por ejemplo, Nothing?).
- Nothingya ha cerrado el script de expresión nula, y esta función será completamente redundante la mayor parte del tiempo.
- En todas partes, toda la documentación y todas las instrucciones deben actualizarse para recomendar el uso de una nueva sintaxis, que básicamente declara Nothingobsoleto para la mayoría de los escenarios.
- Nothingy- Nullse comportarán igual en tiempo de ejecución con respecto a la vinculación tardía, las transformaciones, etc.
- Puede ser como un arma en un apuñalamiento.
Algo asi.
Offtopic (pero relacionado)Aquí hay un ejemplo muy similar al segundo anterior, pero sin inferencia de tipos:
 Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) End Sub End Module 
código fuente de githubEste programa muestra 0. Se comporta exactamente igual que el segundo ejemplo, por la misma razón, pero ilustra un problema separado, aunque relacionado. Intuitivamente, ¿qué es 
Dim i as Integer? = If(False, 1, Nothing) Dim i as Integer? = If(False, 1, Nothing) comporta igual que 
Dim i As Integer? : If False Then i = 1 Else i = Nothing Dim i As Integer? : If False Then i = 1 Else i = Nothing . En este caso, esto no es así, porque la expresión condicional 
(If) no "pasa" información del tipo final a sus operandos. Resulta que esto desglosa todas las expresiones en VB que se basan en lo que se llama la tipificación final (contextual) ( 
Nothing , 
AddressOf , una matriz de literales, expresiones lambda y cadenas interpoladas) con problemas que van desde la compilación en general hasta la creación silenciosa de valores incorrectos para lanzando ruidosamente excepciones. Aquí hay un ejemplo de una opción sin compilar:
 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 
código fuente de githubEste programa no se compilará. En cambio, informa un error en la expresión 
If que no puede determinar el tipo de expresión cuando ambas expresiones 
AddressOf están destinadas 
AddressOf a recibir delegados 
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 .
? 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() .
? , 
'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# , , .
? , , VB , C# ( ). , ( , ), … , .
, VB , VB , , , , , ( 
#6 ). VB . , VB 2002 .
51 52. (Partial-name qualification & Smart-name resolution)
:
- , — ( ). SystemSystem.Windows.Forms— , ,SystemSystem.WindowsSystem.WindowsSystem.Windows.Forms.
- , , , . SystemWindows,WindowsForm.
, , . . 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.PropertyChangedEventArgsSystem.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 .
? , VB. , . 2008 VB C# «» {}, - ( , , ). , , , + , . .
56.
, LINQ. , .
, , 
.
57. CType, DirectCast C#
/ VB C#.
VB 
CType :
- ;
- ( );
- , , LongInteger(. «»);
- (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#. . , .
? . , , , , .
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, - . + , , - . Por qué :
- “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) .
, , , , , . , , .
? 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# (==, !=, >, <, >=, <=) boolbool?
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.
Algo asi.
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#, . , ( , ), - .
? , , , . , , 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 .
? . VB . , 
For Each x As T In collection , 
As T . 
From As For Each ( , 
As ).
71-75. Select , ,
Por ejemplo:
- 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$), .
? ( 
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 ( 
— .. ).
Minuto de publicidad. 15-16 - .NET- DotNext 2019 Piter . , . , . .