Una lista exhaustiva de diferencias entre VB.NET y C #. Parte 2

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


Texto oculto

Conversiones



Expresiones



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 github

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

  1. Nada adquiere un tipo significativo, y ...
  2. 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 github

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

Entendido, ¿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 github

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

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

Este 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 

GitHub

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

GitHub

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

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 .

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

  • «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, - . + , , - . 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 

GitHub

s = "" 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?) ' 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.
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 '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#, . , ( , ), - .

? , , , . , , 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} ' 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 ( — .. ).

Minuto de publicidad. 15-16 - .NET- DotNext 2019 Piter . , . , . .

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


All Articles