Uma lista exaustiva de diferenças entre VB.NET e C #. Parte 2

Na primeira parte do artigo, o tópico superioridade do VB.NET sobre o C # em termos de classificação do TIOBE encontrou uma resposta animada nos comentários. Portanto, seguindo os conselhos do AngReload, vamos analisar as tendências do StackOverflow.

C # ainda é forte! A revolução de que se falou há tanto tempo foi cancelada! Viva, camaradas! Ou não? A classificação TIOBE é baseada em consultas de mecanismos de pesquisa e a classificação SO é baseada em tags de perguntas feitas. Talvez os desenvolvedores do VB.NET, que incluem muitas pessoas que não têm especialidades, simplesmente não conheçam a existência do StackOverflow? Ou, tendo chegado lá pelo Google, ou mesmo pelo Bing, não entende como fazer uma pergunta? Ou talvez eles tenham documentação suficiente da Miscrosoft e todas as poucas perguntas já tenham sido respondidas.

De uma maneira ou de outra, a participação do VB.NET é perceptível e estável, embora não em primeiro lugar em termos de volume. E, é claro, esse resultado não teria sido possível sem uma equipe forte de designers e desenvolvedores de idiomas. Abaixo está a segunda parte da tradução de um artigo por um membro dessa equipe, Anthony Green .

Conteúdo


Texto oculto

Conversões



Expressões



Conversões


34. Transformações booleanas


A conversão de Boolean True para qualquer tipo numérico assinado gera -1 e, para qualquer tipo não assinado, fornece o valor máximo para esse tipo, enquanto que em C # não existem essas conversões. No entanto, o método Convert.ToInt32 , por exemplo, converte True em 1 e é assim que ele é representado com mais freqüência em IL . Na direção oposta, qualquer número diferente de 0 é convertido em True .

Porque O motivo pelo qual o VB prefere usar de -1 a 1 é porque a negação bit a bit de 0 (todos os bits estão definidos como 0) em qualquer idioma é -1 (todos os bits estão definidos como 1 ); portanto, esse valor combina lógica e bit a bit operações como And , Or e Xor .
Conversões de e para as linhas "Verdadeiro" e "Falso" também são suportadas (é claro, não diferenciam maiúsculas de minúsculas).

35. As conversões entre os tipos de Enum, bem como entre os tipos de Enum e seus tipos de base, são completamente ilimitadas, mesmo se Option Strict estiver definido como On


Do ponto de vista filosófico, uma linguagem refere-se a tipos de Enum e não a um conjunto de constantes nomeadas de um tipo inteiro básico. O lugar onde isso é mais óbvio é a igualdade. É sempre permitido comparar qualquer número inteiro com um valor de enumeração, enquanto que em C # isso gera um erro.

Hora da história: A API da Roslyn passou por muitas revisões internas. Mas em cada um deles, uma enumeração SyntaxKind foi alocada para cada idioma, o que informa qual sintaxe o nó representa (por exemplo, IfStatement , TryCastExpression ). Uma vez, um desenvolvedor usou uma API que tentou abstrair do idioma e retornou um dos valores SyntaxKind , mas apenas como Integer , e sem receber erros ao comparar Integer bruto e SyntaxKind , esse desenvolvedor veio imediatamente ao meu escritório e reclamou: “int is detalhes de implementação, eu deveria ter sido forçado a fazer um elenco! ” .

Ao longo dos anos, durante a próxima revisão da API, removemos completamente as propriedades ( Property Kind As SyntaxKind ), que apontavam para um tipo específico de idioma, e todas as APIs começaram a retornar Integer . Todo o código C # quebrou e todo o código VB continuou a funcionar como se nada tivesse acontecido.

Um pouco mais tarde, decidimos renomear essa propriedade para RawKind e adicionar métodos de extensão específicos do idioma Kind() . Todo o código C # quebrou porque eram necessários parênteses para chamar métodos, mas, como não eram necessários no VB, todo o código VB continuou a funcionar novamente como se nada tivesse acontecido.

36. A verificação de estouro / estouro negativo para aritmética inteira é completamente controlada pelo ambiente de compilação (configurações do projeto), mas VB e C # usam valores padrão diferentes; no VB, a verificação de estouro é ativada por padrão


Tipos integrais têm um intervalo; portanto, por exemplo, o Byte pode representar valores de 0 a 255. Então, o que acontece quando você adiciona o Byte 1 ao Byte 255? Se a verificação de estouro / estouro estiver desativada, o valor será rolado para 0. Se o tipo for assinado, ele será rolado para o número negativo mais baixo (por exemplo, -128 para SByte ). Provavelmente isso indica um erro no seu programa. Se a verificação de estouro / estouro estiver ativada, uma exceção será lançada. Para entender o que quero dizer, dê uma olhada nesse loop For inofensivo.

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

código fonte do github

Por padrão, esse loop lançará uma exceção no VB (uma vez que a última iteração do loop ultrapassa a borda Byte . Mas com a verificação de estouro desativada, ele faz um loop porque depois de 255 i se torna 0 novamente.
Subfluxo é a situação oposta ao subtrair abaixo do valor mínimo para o tipo, resultando no valor máximo.

Uma situação de estouro mais comum é simplesmente a adição de dois números. Pegue os números 130 e 150, ambos como Byte . Se você reuni-los, a resposta é 280, que não se encaixa no Byte. Mas seu processador não percebe isso. Em vez disso, ele relata que a resposta é 24.

A propósito, isso não tem nada a ver com conversões. Adicionar dois bytes fornece um byte; é assim que a matemática binária funciona. Embora você também possa exceder executando uma conversão, por exemplo, ao tentar converter Longo em Inteiro. Sem verificar se há transbordamento, o programa simplesmente corta os bits e os materiais extras, tanto quanto se encaixa nessa variável.

Qual a diferença? Performance. A verificação do CLR quanto ao estouro requer um tempo computacional um pouco mais comparado à opção sem verificação, como todas as outras verificações de segurança. O VB é baseado na filosofia de que a produtividade do desenvolvedor é mais importante que o desempenho computacional; portanto, por padrão, você tem a verificação de segurança ativada. A equipe de desenvolvimento de C # hoje pode tomar uma decisão diferente sobre as configurações padrão do projeto, mas, considerando que os primeiros desenvolvedores de C # vieram de desenvolvedores de C / C ++, esse grupo de pessoas provavelmente exigiria que o código não fizesse mais nada, o que poderia custar ciclos do processador ; essa é uma diferença filosófica difícil .

Nuance: mesmo se a verificação de estouro / estouro estiver desativada, a conversão dos valores PositiveInfinity , NegativeInfinity , NaN de Single ou Double em Decimal lançará uma exceção, pois nenhum desses valores pode, em princípio, ser representado em decimal.

37. A conversão de números de ponto flutuante em tipos inteiros utiliza arredondamentos de banqueiros em vez de truncar


Se você converter 1,7 para um número inteiro em VB, o resultado será 2. Em C #, o resultado será 1. Não posso dizer nada sobre regras matemáticas fora dos Estados Unidos, mas quando alterno de um número real para um número inteiro, arredondo instintivamente. E nenhum daqueles que conheço fora do círculo de programadores acredita que o número inteiro mais próximo de 1,7 é 1.

Na verdade, existem vários métodos de arredondamento, e o tipo de arredondamento usado no VB (e no método Math.Round) é chamado arredondamento de banco ou arredondamento estatístico por padrão. Sua essência é que, para um número no meio entre dois números inteiros, VB arredonda para o número par mais próximo. Portanto, 1,5 é arredondado para 2 e 4,5 é arredondado para 4. O que realmente não funciona da maneira como fomos ensinados na escola - fui ensinado a arredondar para 0,5 (tecnicamente, arredondar para o lado a partir do zero). Mas, como o nome indica, o arredondamento bancário tem a vantagem de que, com um grande número de cálculos, você se divide ao arredondar ao meio e nem sempre cede ou sempre guarda dinheiro. Em outras palavras, em um conjunto grande, isso limita a distorção dos dados ao desvio estatístico final.

De onde vem a diferença? O arredondamento é mais intuitivo e prático, truncando mais rapidamente. Se você considerar usar o VB em aplicativos LOB, e especialmente em aplicativos como as macros do Excel executadas no VBA, simplesmente largar casas decimais pode causar ... problemas.

Eu acho que é óbvio que o método de conversão é sempre uma questão controversa e deve ser indicada explicitamente, mas se você precisar escolher uma única ...

38. Não é um erro converter classes NotInheritable para / de interfaces que elas não implementam em tempo de compilação


De um modo geral, se você estiver verificando uma classe NonInheritable para uma implementação de interface, poderá entender em tempo de compilação se essa conversão é possível porque você conhece todas as interfaces desse tipo e todos os seus tipos básicos. Se o tipo é herdado, você não pode ter certeza de que essa conversão é impossível, porque o tipo do objeto de tempo de execução mencionado pode de fato ter um tipo mais derivado que implementa essa interface. No entanto, há uma exceção devido à interoperabilidade COM, quando, em tempo de compilação, pode não ser visível que o tipo tenha algo a ver com a interface, mas, em tempo de execução, ocorrerá. Por esse motivo, o compilador VB gera um aviso nesses casos.

Porque VB e COM cresceram juntos quando eram crianças no bairro antigo. Portanto, existem várias soluções no design de linguagem nas quais o VB presta muita atenção às coisas que existiam apenas no COM no momento do lançamento do .NET 1.0.

39. Tentar descompactar (unbox) null em um tipo significativo resulta em um valor padrão do tipo, não em NullReferenceException


Eu acredito que tecnicamente isso também é verdade para tipos de referência, mas sim:
 CInt(CObj(Nothing)) = 0 

Porque Porque CInt(Nothing) = 0 , e o idioma tende a ser um pouco consistente, independentemente de você ter digitado suas variáveis ​​ou não. Isso se aplica a qualquer estrutura, não apenas aos tipos significativos internos. Veja o raciocínio em # 25 para mais detalhes.

40. O desempacotamento suporta conversões de tipo primitivo


Tanto em VB quanto em C #, você pode converter Short em Integer , mas e se você tentar converter Short em Integer ? Em VB Short será primeiro descompactado e depois convertido em Integer . Em C #, a menos que você descompacte manualmente antes de converter para int , uma InvalidCastException será lançada.
Isso se aplica a todas as conversões internas, ou seja, tipos numéricos compactados, conversões entre strings e tipos numéricos, strings e datas (sim, decimal e data são tipos primitivos).

Porque Novamente, para garantir um comportamento consistente, independentemente de seu programa ser totalmente digitado, digitado como Objeto ou ser refatorado de uma opção para outra. Veja o item 39 acima.

41. Há conversões entre String e Char


  • String convertida em Char , representando seu primeiro caractere.
  • Char convertido em String única maneira razoável.

Porque ninguém, exceto eu, se lembra da sintaxe de um caractere literal no VB (e não deveria).

42. Há conversões entre as String e Char


  • String convertida em uma matriz Char consiste em todos os seus caracteres.
  • A matriz Char é convertida em uma String consiste em todos os seus elementos.

Por definição: essas transformações criam novos objetos, você não obtém acesso à estrutura String interna.

História engraçada: Uma vez encontrei (ou talvez o relatei e estava pesquisando) quebrando alterações entre o .NET 3.5 e 4.0, porque entre essas versões a equipe do .NET adicionou o modificador ParamArray ao segundo String.Join sobrecarga String.Join , que utiliza uma matriz de strings . As suposições exatas são perdidas no tempo (provavelmente para melhor), mas, como acredito, o motivo é que, com o modificador ParamArray agora você pode converter uma matriz Char em uma string e passá-la como um elemento separado para a matriz de parâmetros. Tema divertido.

43 e 44. Conversões de String para tipos numéricos e de data suportam sintaxe literal (normalmente)


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

Isso funciona com prefixos de base e torna possível usar uma maneira muito conveniente de converter entrada hexadecimal (ou octal) em um número: CInt("&H" & input) . Infelizmente, essa simetria está se degradando no momento da redação deste artigo, porque o tempo de execução do VB não foi atualizado para oferecer suporte ao prefixo binário & B ou ao 1_000 grupo de 1_000 dígitos, mas espero que isso seja corrigido na próxima versão. A notação científica funciona, mas sem sufixos de tipo, e as conversões de data também suportam formatos de data padrão; portanto, o formato JSON usado na ISO-8601 também funciona: CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM# .

Porque Não conheço outro motivo senão conveniência. Mas eu realmente gostaria de oferecer suporte a outros formatos comuns quase onipresentes na rede hoje, como #FF, U + FF, 0xFF. Eu acho que isso poderia facilitar muito a vida em alguns tipos de aplicações ...

45. NÃO conversões entre Char e tipos inteiros


O QUE?!?!?
Depois de ler sobre todas essas transformações adicionais, você está surpreso? O VB proíbe conversões entre Char e Integer :

  • CInt("A"c) não compila.
  • CChar(1) não compila.

Porque Não está claro o que vai acontecer. Geralmente, o VB nessas situações usa uma abordagem pragmática e / ou intuitiva, mas para a expressão CInt("1") , acho que metade dos leitores esperaria o número 1 (valor do caractere 1) e metade esperaria o número 49 (código ASCII / UTF para caractere 1). Em vez de fazer a escolha errada na metade dos casos, o VB possui funções especiais para converter caracteres em códigos ASCII / Unicode e vice-versa, AscW e ChrW respectivamente.

Expressões


46. ​​Nada <> nulo


O literal Nothing no VB não significa nulo . Significa "o valor padrão para o tipo para o qual é usado" e acontece que, para tipos de referência, o valor padrão é nulo. A diferença só importa quando usada em um contexto em que:

  1. Nada assume um tipo significativo, e ...
  2. Não está claro pelo contexto que ele está fazendo isso.

Vejamos alguns exemplos que ilustram o que isso significa.

O primeiro, talvez um pouco estranho, mas não acho que a maioria das pessoas fique impressionada com o entendimento de que este programa imprimirá "Verdadeiro":

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

código fonte do github

O motivo é bem simples: você está comparando Integer (0) com o valor padrão de seu tipo (também 0). O problema ocorre no VB2005 / 2008 quando você adiciona tipos significativos anuláveis. Veja este exemplo:

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

código fonte do github

Entendido, como alguém pode sugerir que o tipo i é um Integer? ( Nullable(Of Integer) ). Mas não é assim, porque Nothing obtém o tipo do contexto, e o único tipo nesse contexto vem do segundo operando, e este é um non-nullable Integer simples e non-nullable Integer (tecnicamente, Nothing nunca tem um tipo). Outra maneira de analisar esse problema é com o seguinte exemplo:

 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 fonte do github

Novamente, aqui, intuitivamente, parece que Nothing adiciona uma dica "anulável" e que o idioma seleciona uma sobrecarga que aceita nullable , mas não aceita (seleciona non-nullable , porque é "mais específico"). No mínimo, pode-se assumir que, como nulo em C #, a expressão Nothing não se aplica a Integer , e que a sobrecarga anulável será selecionada pelo método de exceção, mas isso se baseia novamente na ideia errada de que Nothing = null (Is null?) .

Nuance: Uma nova expressão default foi adicionada no C # 7.1 que corresponde a Nothing no VB. Se você reescrever todos os três exemplos acima em C # usando o default vez de null , obtém exatamente o mesmo comportamento .

O que pode ser feito sobre isso? Existem várias sugestões, mas nenhuma ganhou ainda:

  • Mostrar um aviso sempre que Nothing convertido em um tipo significativo e não é null em um tipo significativo que pode ser nullable .
  • Expanda lindamente Nothing para 0 , 0.0 , ChrW(0) , False , #1/1/0001 12:00:00 AM# ChrW(0) #1/1/0001 12:00:00 AM# ou New T (o valor padrão para qualquer estrutura) toda vez que seu valor em tempo de execução for um dos listados acima.
  • Adicione uma nova sintaxe que significa "Nulo, não, sério!", Como Null ou Nothing?
  • Adicione uma nova sintaxe na forma de um sufixo (?) Que agrupe o valor em anulável para ajudar a deduzir o tipo, por exemplo, If(False, 0?, Nothing)
  • Adicione operadores de conversão anuláveis ​​para tipos internos para facilitar a sugestão de inferência de tipos, por exemplo, If (False, CInt? (0), Nothing)

Gostaria de ouvir seus pensamentos nos comentários e / ou no Twitter .

Então, para resumir:

  • Antigos tempos - VB6 e VBA têm "Nothing", "Null", "Empty" e "Missing", significando coisas diferentes.
  • 2002 - no VB.NET há apenas Nothing (o valor padrão em um contexto específico) e em C # - somente null .
  • 2005 - O C # adiciona o default(T) (um valor padrão do tipo T ), porque os genéricos recém-adicionados criam uma situação em que você precisa inicializar um valor, mas não sabe se é um tipo de referência ou significativo; O VB não faz nada porque esse script já está fechado por Nothing .
  • 2017 - C # adiciona default (valor default no contexto), pois há muitos cenários em que especificar T redundante ou impossível

O VB continua resistindo à adição de uma expressão Null (ou equivalente) porque:

  • A sintaxe estará quebrando as alterações.
  • A sintaxe não quebrará as mudanças, mas, dependendo do contexto, significará coisas diferentes.
  • A sintaxe será muito discreta (por exemplo, Nothing? ); Imagine que você precisa falar em voz alta sobre o Nothing e o Nothing? para explicar algo para uma pessoa.
  • A sintaxe pode ser muito feia (por exemplo, Nothing? ).
  • O script de expressão nula já está fechado por Nothing e essa função será completamente redundante na maioria das vezes.
  • Em todos os lugares, toda a documentação e todas as instruções devem ser atualizadas para recomendar o uso de nova sintaxe, que basicamente declara Nothing obsoleto na maioria dos cenários.
  • Nothing e Null ainda se comportarão da mesma forma em tempo de execução com relação a ligação tardia, transformações etc.
  • Pode ser como uma arma em uma facada.

Algo assim.

Offtopic (mas relacionado)

Aqui está um exemplo muito semelhante ao segundo acima, mas sem inferência de tipo:

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

código fonte do github

Este programa exibe 0. Ele se comporta exatamente da mesma forma que o segundo exemplo, pelo mesmo motivo, mas ilustra um problema separado, embora relacionado. Intuitivamente, o que é Dim i as Integer? = If(False, 1, Nothing) Dim i as Integer? = If(False, 1, Nothing) se comporta da mesma forma 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 . Nesse caso, não é assim, porque a expressão condicional (If) não “passa” informações do tipo final para seus operandos. Acontece que isso divide todas as expressões no VB que dependem do que é chamado de digitação final (contextual) ( Nothing , AddressOf , uma matriz de literais, expressões lambda e seqüências de caracteres interpoladas) com problemas que variam de não compilação em geral a criar discretamente valores incorretos para jogando alto exceções. Aqui está um exemplo de uma opção não compilada:

 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 fonte do github

Este programa não será compilado. Em vez disso, ele relata um erro na expressão If que não pode determinar o tipo de expressão quando ambas as expressões AddressOf se destinam AddressOf a receber 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.ioBoundParenthesized VB C#. , , .

48. Me


VB.NET Me . , - , — , Me Structure . Me . C# this , this .

49.


VB, , :

 Class C Sub M() Extension() End Sub End Class Module Program Sub Main() End Sub <Runtime.CompilerServices.Extension> Sub Extension(c As C) End Sub End Module 

GitHub

C# ( something.Extension). , C#, , this.Extension() .

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

  • “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 = NULLNULL , TRUE.
, :

. Null , , , C# .

. C# VB, « null?» C# (if (value == null)) . VB , VB (=/<>) (Is/IsNot) , VB Is Nothing non-nullable Boolean .

, VB null, null. And/AndAlso Or/OrElse .

Integer? ( ), VB, C# null, :

  • 1 AND NULL NULL
  • 1 OR NULL NULL

Boolean? , VB .

  • FALSE AND NULL FALSE
  • TRUE OR NULL TRUE
  • TRUE AND NULL NULL
  • FALSE OR NULL NULL

, True/False , , null. , AndAlso OrElse .

C# (&&/||) (&/|) nullable boolean (bool?) . , , non-nullable boolean nullable boolean .

?
VB , - :

 Imports System.ComponentModel Class BindableRange Implements INotifyPropertyChanged Property _EndDate As Date? Property EndDate As Date? Get Return _EndDate End Get Set(value As Date?) ' This line here: If value = _EndDate Then Return _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End Set End Property Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged End Class Module Program WithEvents Range As New BindableRange Sub Main() Range.EndDate = Today Range.EndDate = Today Range.EndDate = Nothing Range.EndDate = Nothing End Sub Private Sub BindableRange_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles Range.PropertyChanged Console.WriteLine(e.PropertyName & " changed.") End Sub End Module 

GitHub

, , , , «EndDate change» . , , VB null ? , EndDate , , , Nothing .

VB : «, , . » :
 If value <> _EndDate Then _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End If 

! . , non-nullable . , . , :
 If value Is Nothing AndAlso _EndDate Is Nothing Then Return If value <> _EndDate Then Return 

?
, C# , VB. ( nullable , ), , null.

null — «» « » . .

null « » «» . , , : comparer, , comparer . Roslyn, Optional(Of T) , , , null, , .

, NULL « », VB :

  • , « , ?» « ».
  • : « , ?» « ».

, , SQL- . , NULL SQL , NULL. . , , NULL . , . , , ( ). , , , , , NULL , SQL ( ).

VB. nullable 2008 , VB ?
LINQ to SQL

VB , , , , , , LINQ- . !

. SQL Server, , SET ANSI_NULLS OFF , SQL- C#, WHERE Column = NULL . , , OFF ( ). SQL Server ( ) . : « ? . , - Option ANSI_NULLS Off VB.NET?» . :



, , , , , SQL Server, VB.
Algo assim.

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

  • From x In y Where x > 10 . , Select .
  • From x In y Select x Where x > 10 .
  • From x In y Select x , From x In y Select x = x , xx , xSelect . Select .
  • From x In y Select z = x.ToString() , x .
  • From x In y Select x.FirstName , From x In y Select FirstName = x.FirstName .
  • From x In y Select x.FirstName, x.LastNameFrom x In y Select New With {x.FirstName, y.LastName} , , . IEnumerable(Of $AnonymousType$) , .

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

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


All Articles