Daftar lengkap perbedaan antara VB.NET dan C #. Bagian 2

Pada bagian pertama artikel, topik keunggulan VB.NET atas C # dalam hal peringkat TIOBE menemukan tanggapan yang hidup di komentar. Oleh karena itu, atas saran AngReload, mari kita lihat tren StackOverflow.

C # masih kuat! Revolusi yang telah dibicarakan begitu lama terakhir kali dibatalkan! Hore, kawan! Atau tidak? Peringkat TIOBE didasarkan pada permintaan mesin pencari, dan peringkat SO didasarkan pada tag dari pertanyaan yang diajukan. Mungkin para pengembang VB.NET, yang mencakup banyak orang yang tidak memiliki spesialisasi, sama sekali tidak tahu tentang keberadaan StackOverflow? Atau telah sampai di sana melalui Google, atau bahkan Bing, tidak mengerti bagaimana cara mengajukan pertanyaan? Atau mungkin mereka memiliki cukup dokumentasi Miscrosoft, dan semua pertanyaan sudah dijawab.

Salah satu cara atau yang lain, pangsa VB.NET terlihat dan stabil, meskipun tidak di tempat pertama dalam hal volume. Dan, tentu saja, hasil seperti itu tidak akan mungkin terjadi tanpa tim desainer dan pengembang bahasa yang kuat. Di bawah ini adalah bagian kedua dari terjemahan artikel oleh anggota tim ini, Anthony Green .

Isi


Teks tersembunyi

Konversi



Ekspresi



Konversi


34. Transformasi Boolean


Mengonversi Boolean True ke jenis numerik apa pun yang ditandatangani menghasilkan -1 , dan untuk jenis apa pun yang tidak ditandatangani itu memberikan nilai maksimum untuk jenis ini, sedangkan di C # tidak ada konversi seperti itu. Namun, metode Convert.ToInt32 , misalnya, mengkonversi True ke 1 , dan itulah yang paling sering diwakili dalam IL . Di arah yang berlawanan, angka apa pun selain 0 dikonversi ke True .

Mengapa Alasan VB lebih suka menggunakan dari -1 ke 1 adalah karena negasi bitwise dari 0 (semua bit diatur ke 0) dalam bahasa apa pun adalah -1 (semua bit diatur ke 1 ), jadi menggunakan nilai ini menggabungkan logis dan bitwise operasi seperti And , Or dan Xor .
Konversi ke dan dari baris "Benar" dan "Salah" juga didukung (tentu saja, tidak peka huruf besar kecil).

35. Konversi antara tipe Enum dan juga antara tipe Enum dan tipe dasarnya sepenuhnya tidak terbatas, bahkan jika Pilihan Ketat diatur ke Aktif


Dari sudut pandang filosofis, suatu bahasa merujuk pada tipe-tipe Enum dan bukan seperangkat konstanta bernama dari tipe integer dasar. Tempat yang paling jelas adalah kesetaraan. Selalu diizinkan untuk membandingkan bilangan bulat apa pun dengan nilai enumerasi, sedangkan di C # ini memberikan kesalahan.

Waktu Cerita: API Roslyn telah melalui banyak revisi internal. Tetapi di masing-masing dari mereka, sebuah enumerasi SyntaxKind dialokasikan untuk setiap bahasa, yang memberi tahu Anda apa sintaks yang dilambangkan simpul (misalnya, IfStatement , TryCastExpression ). Suatu ketika, seorang pengembang menggunakan API yang mencoba abstrak dari bahasa dan mengembalikan salah satu nilai SyntaxKind , tetapi hanya sebagai Integer , dan tanpa menerima kesalahan ketika membandingkan Integer dan SyntaxKind baku, pengembang ini segera datang ke kantor saya dan mengeluh: “int adalah detail implementasi, saya seharusnya dipaksa melakukan pemeran! " .

Selama bertahun-tahun, selama revisi API berikutnya, kami sepenuhnya menghapus properti ( Property Kind As SyntaxKind ), yang mengarah ke jenis bahasa tertentu, dan semua API mulai mengembalikan Integer . Semua kode C # rusak, dan semua kode VB terus bekerja seolah-olah tidak ada yang terjadi.

Beberapa saat kemudian, kami memutuskan untuk mengubah nama properti ini menjadi RawKind dan menambahkan metode ekstensi khusus bahasa Kind() . Semua kode C # rusak karena tanda kurung diperlukan untuk memanggil metode, tetapi karena mereka tidak diperlukan dalam VB, semua kode VB terus bekerja kembali seolah-olah tidak ada yang terjadi.

36. Memeriksa overflow / overflow negatif untuk bilangan bulat aritmatika sepenuhnya dikendalikan oleh lingkungan kompilasi (pengaturan proyek), tetapi VB dan C # menggunakan nilai default yang berbeda; di VB, pengecekan overflow diaktifkan secara default


Tipe integral memiliki rentang, jadi, misalnya, Byte dapat mewakili nilai dari 0 hingga 255. Jadi, apa yang terjadi ketika Anda menambahkan Byte 1 ke Byte 255? Jika pemeriksaan overflow / underflow dinonaktifkan, nilainya bergulir ke 0. Jika jenisnya ditandatangani, akan menggulir ke angka negatif terendah (misalnya, -128 untuk SByte ). Ini kemungkinan besar menunjukkan kesalahan dalam program Anda. Jika pemeriksaan overflow / underflow diaktifkan, pengecualian dilemparkan. Untuk memahami apa yang saya maksud, lihat loop For berbahaya ini.

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

kode sumber github

Secara default, loop ini akan melempar pengecualian dalam VB (karena iterasi terakhir dari loop melampaui batas Byte . Tetapi dengan cek overflow dimatikan, loop karena setelah 255 i menjadi 0 lagi.
Underflow adalah situasi yang berlawanan ketika mengurangi di bawah nilai minimum untuk jenis menghasilkan nilai maksimum.

Situasi overflow yang lebih umum hanyalah penambahan dua angka. Ambil angka 130 dan 150, keduanya sebagai Byte . Jika Anda menyatukannya, jawabannya adalah 280, yang tidak sesuai dengan Byte. Tetapi prosesor Anda tidak merasakan ini. Sebagai gantinya, ia melaporkan bahwa jawabannya adalah 24.

Omong-omong, ini tidak ada hubungannya dengan konversi. Menambahkan dua byte memberikan satu byte; ini hanya cara matematika biner bekerja. Meskipun Anda juga bisa mendapatkan overflow dengan melakukan konversi, misalnya, ketika mencoba mengkonversi Long ke Integer. Tanpa memeriksa overflow, program hanya memotong bit dan barang ekstra sesuai dengan variabel ini.

Apa bedanya? Performa. Memeriksa CLR untuk overflow membutuhkan waktu komputasi sedikit lebih banyak dibandingkan dengan opsi non-pengecekan, seperti semua pemeriksaan keamanan lainnya. VB didasarkan pada filosofi bahwa produktivitas pengembang lebih penting daripada kinerja komputasi, jadi secara default Anda mengaktifkan pemeriksaan keamanan. Tim pengembang C # hari ini dapat membuat keputusan yang berbeda pada pengaturan default proyek, tetapi mengingat bahwa pengembang C # pertama berasal dari pengembang C / C ++, kelompok orang ini mungkin akan meminta agar kode tidak melakukan apa-apa lagi, yang dapat menghabiskan siklus prosesor ; ini adalah perbedaan filosofis yang sulit .

Nuansa: bahkan jika pemeriksaan overflow / underflow dimatikan, konversi PositiveInfinity , NegativeInfinity , NaN dari tipe Single atau Double ke Decimal menghasilkan pengecualian, karena tidak satu pun dari nilai-nilai ini secara prinsip dapat diwakili dalam Decimal.

37. Mengubah angka floating point ke tipe integer menggunakan pembulatan bankir daripada memotong


Jika Anda mengonversi 1,7 menjadi bilangan bulat di VB, hasilnya adalah 2. Di C #, hasilnya adalah 1. Saya tidak bisa mengatakan apa-apa tentang aturan matematika di luar Amerika, tetapi ketika saya beralih dari bilangan real ke bilangan bulat, saya secara naluriah membulat. Dan tidak ada yang saya tahu di luar lingkaran programmer percaya bahwa bilangan bulat terdekat ke 1,7 adalah 1.

Sebenarnya ada beberapa metode pembulatan, dan jenis pembulatan yang digunakan dalam VB (dan dalam metode Math.Round) disebut pembulatan bank atau pembulatan statistik secara default. Esensinya adalah bahwa untuk bilangan di tengah antara dua bilangan bulat, VB membulatkan ke bilangan genap terdekat. Jadi 1,5 dibulatkan menjadi 2, dan 4,5 dibulatkan menjadi 4. Apa yang sebenarnya tidak berhasil seperti yang diajarkan kepada kita di sekolah - saya diajarkan untuk mengumpulkan dari 0,5 (secara teknis, putaran ke sisi dari nol). Tapi, seperti namanya, pembulatan bank memiliki keuntungan bahwa dengan sejumlah besar perhitungan, Anda membagi ketika membulatkan menjadi dua, dan tidak selalu memberikan atau selalu menyimpan uang. Dengan kata lain, pada perangkat besar, ini membatasi distorsi data ke penyimpangan statistik utama.

Dari mana perbedaan itu berasal? Pembulatan lebih intuitif dan praktis, memotong lebih cepat. Jika Anda mempertimbangkan untuk menggunakan VB dalam aplikasi LOB, dan terutama dalam aplikasi seperti makro Excel yang berjalan pada VBA, cukup menjatuhkan tempat desimal dapat menyebabkan ... masalah.

Saya pikir jelas bahwa metode konversi selalu menjadi masalah yang kontroversial dan harus ditunjukkan secara eksplisit, tetapi jika Anda perlu memilih satu saja ...

38. Ini bukan kesalahan untuk mengkonversi kelas NotInheritable ke / dari antarmuka yang mereka tidak terapkan pada waktu kompilasi


Secara umum, jika Anda memeriksa kelas NonInheritable untuk implementasi antarmuka, Anda dapat memahami pada waktu kompilasi apakah konversi semacam itu dimungkinkan karena Anda mengetahui semua antarmuka jenis ini dan semua jenis dasarnya. Jika jenisnya adalah warisan, Anda tidak dapat memastikan bahwa konversi seperti itu tidak mungkin, karena jenis objek runtime yang dirujuk mungkin sebenarnya memiliki jenis yang lebih diturunkan yang mengimplementasikan antarmuka ini. Namun, ada pengecualian karena COM interop, ketika pada waktu kompilasi mungkin tidak terlihat bahwa jenisnya ada hubungannya dengan antarmuka, tetapi pada saat runtime itu akan terjadi. Untuk alasan ini, kompiler VB menghasilkan peringatan dalam kasus tersebut.

Mengapa VB dan COM tumbuh bersama ketika mereka masih anak-anak di lingkungan lama. Jadi ada beberapa solusi dalam desain bahasa di mana VB memberikan perhatian besar pada hal-hal yang hanya ada di COM pada saat rilis .NET 1.0.

39. Mencoba membongkar (unbox) null ke dalam tipe yang bermakna menghasilkan nilai default dari tipe tersebut, bukan NullReferenceException


Saya percaya bahwa secara teknis ini juga berlaku untuk tipe referensi, tetapi ya:
 CInt(CObj(Nothing)) = 0 

Mengapa Karena CInt(Nothing) = 0 , dan bahasanya cenderung agak konsisten, terlepas dari apakah Anda mengetik variabel Anda atau tidak. Ini berlaku untuk struktur apa pun, bukan hanya tipe bermakna bawaan. Lihat alasannya di # 25 untuk lebih jelasnya.

40. Menghapus kotak mendukung konversi tipe primitif


Di VB dan C # Anda dapat mengonversi Short ke Integer , tetapi bagaimana jika Anda mencoba mengonversi Short to Integer dikemas? Dalam VB Short akan dibongkar terlebih dahulu dan kemudian dikonversi ke Integer . Di C #, kecuali Anda secara manual membuka paket sebelum mengonversi ke int , InvalidCastException akan dilempar.
Ini berlaku untuk semua konversi internal, yaitu tipe numerik yang dikemas, konversi antara string dan tipe numerik, string dan tanggal (ya, Desimal dan Tanggal adalah tipe primitif).

Mengapa Sekali lagi, untuk memastikan perilaku yang konsisten, apakah program Anda diketik sepenuhnya, diketik sebagai Objek, atau sedang di refactored dari satu opsi ke opsi lainnya. Lihat # 39 di atas.

41. Ada konversi antara String dan Char


  • String dikonversi ke Char , mewakili karakter pertamanya.
  • Char dikonversi ke String satu String satunya cara yang masuk akal.

Karena tidak ada seorang pun kecuali saya yang mengingat sintaks karakter literal dalam VB (dan seharusnya tidak).

42. Ada konversi antara String dan array Char


  • String dikonversi ke array Char terdiri dari semua karakternya.
  • Array Char dikonversi menjadi String terdiri dari semua elemennya.

Untuk kepastian: transformasi ini membuat objek baru, Anda tidak mendapatkan akses ke struktur String internal.

Cerita lucu: Saya pernah menemukan (atau mungkin melaporkannya, dan saya sedang meneliti) memecah perubahan antara. NET 3.5 dan 4.0, karena di antara versi-versi ini, tim .NET menambahkan pengubah ParamArray ke String.Join ParamArray kelebihan beban kedua, yang membutuhkan serangkaian string . Asumsi yang tepat hilang dalam waktu (mungkin menjadi lebih baik), tetapi, seperti yang saya percaya, alasannya adalah bahwa dengan pengubah ParamArray Anda sekarang dapat mengubah array Char ke string dan meneruskannya sebagai elemen terpisah ke array parameter. Tema yang menyenangkan.

43 dan 44. Konversi dari String ke tipe numerik dan tanggal mendukung sintaks literal (biasanya)


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

Ini berfungsi dengan awalan basis dan memungkinkan untuk menggunakan cara yang sangat nyaman untuk mengonversi input heksadesimal (atau oktal) ke angka: CInt("&H" & input) . Sayangnya, simetri ini menurun pada saat penulisan ini, karena runtime VB belum diperbarui untuk mendukung awalan biner & B atau 1_000 grup angka 1_000 , tapi saya harap ini diperbaiki di versi berikutnya. Notasi ilmiah berfungsi, tetapi tanpa sufiks tipe, dan konversi tanggal juga mendukung format tanggal standar, sehingga format JSON yang digunakan dalam ISO-8601 juga berfungsi: CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM# .

Mengapa Saya tidak tahu alasan lain selain kenyamanan. Tapi saya benar - benar ingin menawarkan dukungan untuk format umum lainnya yang hampir ada di jaringan saat ini, seperti #FF, U + FF, 0xFF. Saya pikir ini bisa sangat memudahkan kehidupan di beberapa jenis aplikasi ...

45. TIDAK ada konversi antara Char dan tipe integer


APA?!?!?
Setelah membaca tentang semua transformasi tambahan ini, apakah Anda terkejut? VB melarang konversi antara Char dan Integer :

  • CInt("A"c) tidak dapat dikompilasi.
  • CChar(1) tidak dikompilasi.

Mengapa Tidak jelas apa yang akan terjadi. Biasanya VB dalam situasi seperti itu menggunakan pendekatan pragmatis dan / atau intuitif, tetapi untuk ekspresi CInt("1") saya pikir setengah dari pembaca akan mengharapkan angka 1 (nilai karakter 1), dan setengahnya mengharapkan angka 49 (kode ASCII / UTF untuk karakter 1). Alih-alih membuat pilihan yang salah dalam setengah kasus, VB memiliki fungsi khusus untuk mengkonversi karakter ke kode ASCII / Unicode dan sebaliknya, AscW dan ChrW masing-masing.

Ekspresi


46. ​​Tidak ada yang <> nol


Nothing harfiah dalam VB tidak berarti nol . Ini berarti "nilai default untuk tipe yang digunakannya," dan kebetulan bahwa untuk tipe referensi, nilai defaultnya adalah nol. Perbedaan hanya penting ketika digunakan dalam konteks di mana:

  1. Tidak ada yang menggunakan jenis yang signifikan, dan ...
  2. Tidak jelas dari konteksnya bahwa dia melakukan ini.

Mari kita lihat beberapa contoh yang menggambarkan apa artinya ini.

Yang pertama, mungkin agak aneh, tetapi saya tidak berpikir bahwa kebanyakan orang akan diledakkan oleh pemahaman bahwa program ini akan mencetak "Benar":

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

kode sumber github

Alasannya cukup sederhana: Anda membandingkan Integer (0) dengan nilai default dari tipenya (juga 0). Masalahnya terjadi pada VB2005 / 2008 ketika Anda menambahkan jenis bermakna nullable. Lihatlah contoh ini:

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

kode sumber github

Dipahami, bagaimana seseorang menyarankan tipe i itu Integer? ( Nullable(Of Integer) ). Tetapi ini tidak benar, karena Nothing mendapatkan tipe dari konteks, dan satu-satunya tipe dalam konteks ini berasal dari operan kedua, dan ini adalah non-nullable Integer sederhana (secara teknis, Nothing pernah memiliki tipe). Cara lain untuk melihat masalah ini adalah dengan contoh berikut:

 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 

kode sumber github

Sekali lagi, di sini, secara intuitif, tampaknya Nothing menambahkan petunjuk "nullable" dan bahwa bahasa memilih kelebihan yang menerima nullable , tetapi tidak (memilih non-nullable , karena "paling spesifik"). Paling tidak, dapat diasumsikan bahwa, seperti nol dalam C #, ekspresi Nothing tidak berlaku untuk Integer , dan bahwa nullable overload akan dipilih oleh metode pengecualian, tetapi ini sekali lagi didasarkan pada gagasan yang salah bahwa Nothing = null (Is null?) .

Nuansa: Ekspresi default baru telah ditambahkan di C # 7.1 yang cocok dengan Nothing dalam VB. Jika Anda menulis ulang ketiga contoh di atas dalam C # menggunakan default alih-alih null , Anda mendapatkan perilaku yang persis sama .

Apa yang bisa dilakukan tentang ini? Ada beberapa saran, tetapi belum ada yang menang:

  • Tampilkan peringatan setiap kali Nothing dikonversi ke jenis yang bermakna dan itu bukan null dalam jenis signifikan yang dapat null .
  • Perluas dengan indah Nothing ke 0 , 0.0 , ChrW(0) , False , #1/1/0001 12:00:00 AM# ChrW(0) #1/1/0001 12:00:00 AM# atau New T (nilai default untuk setiap struktur) setiap kali nilainya dalam runtime adalah salah satu dari tercantum di atas.
  • Tambahkan sintaks baru yang berarti "Tidak, tidak, sungguh!" Seperti Null atau Nothing?
  • Tambahkan sintaks baru dalam bentuk akhiran (?) Yang membungkus nilai dalam nullable untuk membantu menyimpulkan jenis, misalnya If(False, 0?, Nothing)
  • Tambahkan operator konversi yang dapat dibatalkan untuk tipe bawaan agar lebih mudah memberikan petunjuk untuk mengetik inferensi, misalnya, If (False, CInt? (0), Nothing)

Saya ingin mendengar pendapat Anda di komentar dan / atau di Twitter .

Jadi untuk meringkas:

  • Masa lalu - VB6 dan VBA memiliki "Tidak Ada", "Null", "Kosong" dan "Hilang", artinya berbeda.
  • 2002 - dalam VB.NET hanya Nothing (nilai default dalam konteks tertentu), dan dalam C # - hanya null .
  • 2005 - C # menambahkan default(T) (nilai default tipe T ), karena obat generik yang baru ditambahkan menciptakan situasi di mana Anda perlu menginisialisasi nilai, tetapi Anda tidak tahu apakah itu adalah tipe referensi atau signifikan; VB tidak melakukan apa-apa karena skrip ini sudah ditutup oleh Nothing .
  • 2017 - C # menambahkan default (nilai default dalam konteks) karena ada banyak skenario di mana menentukan T berlebihan atau tidak mungkin

VB terus menolak menambahkan ekspresi Null (atau setara) karena:

  • Sintaks akan melanggar perubahan.
  • Sintaks tidak akan melanggar perubahan, tetapi tergantung pada konteksnya akan berarti hal yang berbeda.
  • Sintaksnya akan terlalu mencolok (misalnya, Nothing? ); Bayangkan Anda perlu berbicara keras tentang Nothing dan Nothing? untuk menjelaskan sesuatu kepada seseorang.
  • Sintaksnya mungkin terlalu jelek (mis. Nothing? ).
  • Skrip ekspresi nol sudah ditutup oleh Nothing , dan sebagian besar waktu fungsi ini akan sepenuhnya berlebihan.
  • Di mana-mana, semua dokumentasi dan semua instruksi harus diperbarui untuk merekomendasikan penggunaan sintaks baru, yang pada dasarnya menyatakan Nothing usang untuk sebagian besar skenario.
  • Nothing dan Null masih akan berperilaku sama dalam runtime sehubungan dengan pengikatan, transformasi, dll.
  • Ini bisa seperti pistol dalam penikaman.

Sesuatu seperti itu.

Offtopic (tetapi terkait)

Berikut adalah contoh yang sangat mirip dengan yang kedua di atas, tetapi tanpa tipe inferensi:

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

kode sumber github

Program ini menampilkan 0. Berperilaku persis sama dengan contoh kedua, untuk alasan yang sama, tetapi menggambarkan masalah yang terpisah, meskipun terkait. Secara intuitif, apa Dim i as Integer? = If(False, 1, Nothing) Dim i as Integer? = If(False, 1, Nothing) berperilaku sama dengan Dim i As Integer? : If False Then i = 1 Else i = Nothing Dim i As Integer? : If False Then i = 1 Else i = Nothing . Dalam hal ini, ini tidak demikian, karena ekspresi kondisional (If) tidak "melewati" informasi dari tipe terakhir ke operan-operasinya. Ternyata ini memecah semua ekspresi dalam VB yang bergantung pada apa yang disebut pengetikan akhir (kontekstual) ( Nothing , AddressOf , array literal, ekspresi lambda dan string yang diinterpolasi) dengan masalah mulai dari tidak kompilasi secara umum hingga diam-diam menciptakan nilai yang salah untuk melempar pengecualian dengan keras. Berikut adalah contoh opsi yang tidak dikompilasi:

 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 

kode sumber github

Program ini tidak akan dikompilasi. Sebagai gantinya, ia melaporkan kesalahan dalam ekspresi If yang tidak dapat menentukan jenis ekspresi ketika kedua ekspresi AddressOf secara AddressOf dimaksudkan untuk menerima delegasi 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, - . + , , - . Mengapa :

  • “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.
Sesuatu seperti itu.

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


Sebagai contoh:

  • 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 ( — .. ).

Menit periklanan. 15-16 - .NET- DotNext 2019 Piter . , . , . .

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


All Articles