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
String
convierte en Char
, que representa su primer carácter.Char
convierte 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
String
convierte en una matriz Char
consta de todos sus caracteres.- La matriz
Char
se convierte en una String
consta 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
Nothing
convierte en un tipo significativo y no es null
en un tipo significativo nullable
. - Expanda maravillosamente
Nothing
a 0
, 0.0
, ChrW(0)
, False
, #1/1/0001 12:00:00 AM#
ChrW(0)
#1/1/0001 12:00:00 AM#
o New 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
Null
o Nothing?
- 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 #, solo null
. - 2005: C # agrega el
default(T)
(un valor predeterminado del tipo T
), 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 por Nothing
. - 2017: C # agrega el
default
(valor default
en contexto) ya que hay muchos escenarios en los que especificar T
redundante 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 sobre Nothing
and Nothing?
para explicarle algo a una persona. - La sintaxis puede ser demasiado fea (por ejemplo,
Nothing?
). Nothing
ya 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
Nothing
obsoleto para la mayoría de los escenarios. Nothing
y Null
se 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)
:
- , — ( ).
System
System.Windows.Forms
— , , System
System.Windows
System.Windows
System.Windows.Forms
. - , , , .
System
Windows
, Windows
Form
.
, , . . VB Imports ,
using
C# .
, VB
System
,
System
,
System
. , . ,
ExtensionAttribute
,
<Runtime.CompilerServices.Extension>
<System.Runtime.CompilerServices.Extension>
.
C# .
using System
System.Threading
Threading
.
, C# , . ,
System
,
System.Threading
Threading
. , , , , .
, , VB, C# ,
Imports
/
using
, C# using , , using .
(Quantum Namespaces) ( ), ! VB , . ,
System
ComponentModel
System.Windows.Forms
ComponentModel
?
ComponentModel
. ,
ComponentModel.PropertyChangedEventArgs
, ( , ).
System.Windows.Forms
(, , , , ), (ambiguity errors).
VB2015 (Smart Name Resolution),
System
System.Windows.Forms
ComponentModel
, ,
System.ComponentModel
System.Windows.Forms.ComponentModel
, . , , , , . , , , ..
ComponentModel.PropertyChangedEventArgs
System.ComponentModel.PropertyChangedEventArgs
,
System.Windows.Forms.ComponentModel.PropertyChangedEventArgs
. , .
,
Windows
, ( ) ( ) ( ).
WinForms/WPF
UWP
.
53. Add
#33 , VB - , . , , — , :
Class Contact Property Name As String Property FavoriteFood As String End Class Module Program Sub Main() Dim contacts = New List(Of Contact) From { {"Leo", "Chocolate"}, {"Donnie", "Bananas"}, {"Raph", "The Blood of his Enemies"}, {"Mikey", "Pizza"} } End Sub <Runtime.CompilerServices.Extension> Sub Add(collection As ICollection(Of Contact), name As String, favoriteFood As String) collection.Add(New Contact With {.Name = name, .FavoriteFood = favoriteFood}) End Sub End Module
GitHubC# , Roslyn C#, . , (
, ), VS2015.
54. ,
, VB
Dim buffer(expression) As Byte
Dim buffer = New Byte(expression) {}
expression + 1
.
Microsoft BASIC,
DIM
( dimension — ). , , , : 0 expression. Microsoft BASIC 1 ( , 1984), ( ), 2002 .
, - , , VB , BASIC C , , C, C- . ,
buffer(10)
0 10, 9!
55. VB - , C#
, . , VB ( ) , — . :
CType({1, 2, 3}, Short())
CType(New Integer() {1, 2, 3}, Short ())
, Integer
Short
.CType({1, 2, 3}, Short())
New Short() {1, 2, 3}
. .
, , VB , C#. , :
Dim empty As Integer() = {}
:
Dim array As Predicate(Of Char)() = {AddressOf Char.IsUpper, AddressOf Char.IsLower, AddressOf Char.IsWhitespace}
( ):
Dim byteOrderMark As Byte() = {&HEF, &HBB, &HBF} '
.
,
IList(Of T)
,
IReadOnlyList(Of T)
,
ICollection(Of T)
,
IReadOnlyCollection(Of T)
IEnumerable(Of T)
, , ,
ParamArray IEnumerable
.
? , 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#. . , .
? . , , , , .
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# (==, !=, >, <, >=, <=)
bool
bool?
VB ( nullable ) null
null .
Boolean
=
Boolean?
,
True
,
False
null
.
. C#
non-nullable bool
,
.
,
. null. VB
NULL =
NULL —
NULL , TRUE.
, :

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

, , , , , SQL Server, VB.
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 . , . , . .