Access
 sql >> Teknologi Basis Data >  >> RDS >> Access

Fitur Pengubahan Kasus VBA

Sebagai pendukung kuat kontrol versi di Microsoft Access, saya perlu berbicara tentang keluhan terbesar saya dengan lingkungan pengembangan VBA:otomatis "membatalkan" pengidentifikasi. Anggap ini sebagai perluasan dari jawaban saya atas pertanyaan tentang "fitur" ini di stackoverflow.

Saya akan mendekati artikel ini dalam dua bagian. Di Bagian 1, saya akan mendefinisikan perilaku lingkungan pengembangan. Di Bagian 2, saya akan membahas teori saya tentang mengapa ini bekerja seperti ini.

Bagian 1:Mendefinisikan perilaku

Jika Anda telah menghabiskan banyak waktu untuk menulis kode di VBA, saya yakin Anda telah memperhatikan "fitur" ini. Saat Anda mengetik pengidentifikasi—variabel, nama fungsi, enum, dll.—Anda mungkin memperhatikan bahwa IDE secara otomatis mengubah casing pengidentifikasi ini. Misalnya, Anda dapat mengetik nama variabel dalam semua huruf kecil, tetapi segera setelah Anda pindah ke baris baru, huruf pertama variabel Anda  tiba-tiba berubah menjadi huruf besar.

Pertama kali Anda melihat ini bisa menggelegar. Saat Anda melanjutkan pemrograman, IDE terus mengubah casing Anda secara acak. Namun, jika Anda menghabiskan cukup banyak waktu di IDE, akhirnya pola itu akan muncul dengan sendirinya.

Untuk menyelamatkan Anda dari keharusan menghabiskan lebih dari sepuluh tahun dalam hidup Anda menunggu pola itu menampakkan diri kepada Anda, sekarang saya akan menjelaskan pola itu sebagaimana saya telah memahaminya. Sepengetahuan saya,  Microsoft tidak pernah secara resmi mendokumentasikan perilaku ini.

  1. Semua perubahan kasus otomatis bersifat global untuk proyek VBA.
  2. Setiap kali baris deklarasi dari salah satu jenis pengidentifikasi berikut diubah, setiap pengidentifikasi lain dengan nama yang sama juga berubah huruf besarnya:
    • Nama sub
    • Nama fungsi
    • Ketik nama
    • Nama enum
    • Nama variabel
    • Nama tetap
    • Nama properti
  3. Setiap kali nama item enum diubah di mana pun dalam kode, casing nama item enum diperbarui agar sesuai di mana saja.

Mari kita bahas masing-masing perilaku ini lebih detail sekarang.

Perubahan global

Seperti yang saya tulis di atas, perubahan kasus pengenal bersifat global untuk proyek VBA. Dengan kata lain, VBA IDE sepenuhnya mengabaikan ruang lingkup saat mengubah kasus pengidentifikasi.

Misalnya, katakanlah Anda memiliki fungsi pribadi bernama AccountIsActive dalam modul standar. Sekarang, bayangkan modul kelas di tempat lain dalam proyek yang sama. Modul kelas memiliki prosedur Dapatkan Properti pribadi. Di dalam prosedur Dapatkan Properti itu ada variabel lokal bernama accountIsActive . Segera setelah Anda mengetik baris Dim accountIsActive As Boolean ke dalam VBA IDE dan pindah ke baris baru, fungsi Akun Aktif yang kita definisikan secara terpisah dalam modul standarnya sendiri, baris deklarasinya diubah menjadi Private Function accountIsActive() untuk mencocokkan variabel lokal di dalam modul kelas ini.

Itu seteguk, jadi izinkan saya mendemonstrasikannya dengan lebih baik dalam kode.

Langkah 1:Tentukan fungsi AccountIsActive

'--== Module1 ==--
Private Function AccountIsActive() As Boolean
End Function

Langkah 2:Deklarasikan variabel lokal accountIsActive dalam cakupan yang berbeda

'--== Class1 ==--
Private Sub Foo()
    Dim accountIsACTIVE As Boolean
End Sub

Langkah 3:VBA IDE...apa yang telah Anda lakukan?!?!

'--== Module1 ==--
Private Function accountIsACTIVE() As Boolean
End Function

Kebijakan Non-Diskriminasi VBA Case-Obliteration

Tidak puas hanya dengan mengabaikan ruang lingkup, VBA juga mengabaikan perbedaan di antara jenis pengidentifikasi dalam usahanya untuk memaksakan konsistensi casing. Dengan kata lain, setiap kali Anda mendeklarasikan fungsi, subrutin, atau variabel baru yang menggunakan nama pengidentifikasi yang ada, semua contoh pengidentifikasi tersebut diubah huruf besarnya agar sesuai.

Dalam setiap contoh di bawah ini, satu-satunya hal yang saya ubah adalah modul pertama yang terdaftar. VBA IDE bertanggung jawab atas semua perubahan lain pada modul yang telah ditentukan sebelumnya.

Langkah 1:Tentukan fungsi

'--== Module1 ==--
Public Function ReloadDBData() As Boolean
End Function

Langkah 2:Tentukan sub dengan nama yang sama

CATATAN:Ini benar-benar valid selama prosedurnya ada di modul yang berbeda. Yang mengatakan, hanya karena Anda *bisa* melakukan sesuatu, bukan berarti Anda *harus*. Dan Anda *harus* menghindari situasi ini jika memungkinkan.

'--== Module2 ==--
Public Sub ReloadDbData()
End Sub

'--== Module1 ==--
Public Function ReloadDbData() As Boolean
End Sub

Langkah 3:Tentukan jenis dengan nama yang sama

CATATAN:Sekali lagi, jangan mendefinisikan sub, fungsi, dan ketik semua dengan nama yang sama dalam satu proyek.

'--== Module3 ==--
Private Type ReLoadDBData
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub ReLoadDBData()
End Sub

'--== Module1 ==--
Public Function ReLoadDBData() As Boolean
End Sub

Langkah 4:Tentukan enum dengan nama yang sama

CATATAN:Tolong, tolong, tolong, untuk cinta segala sesuatu yang suci...

'--== Module4 ==--
Public Enum ReloadDbDATA
    Dummy
End Enum

'--== Module3 ==--
Private Type ReloadDbDATA
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub ReloadDbDATA()
End Sub

'--== Module1 ==--
Public Function ReloadDbDATA() As Boolean
End Sub

Langkah 5:Tentukan variabel dengan nama yang sama

CATATAN:Kami sebenarnya masih melakukan ini?

'--== Module5 ==--
Public reloaddbdata As Boolean

'--== Module4 ==--
Public Enum reloaddbdata
    Dummy
End Enum

'--== Module3 ==--
Private Type reloaddbdata
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub reloaddbdata()
End Sub

'--== Module1 ==--
Public Function reloaddbdata() As Boolean
End Sub

Langkah 6:Tentukan konstanta dengan nama yang sama

CATATAN:Oh, ayolah. Serius?

'--== Module6 ==--
Private Const RELOADDBDATA As Boolean = True

'--== Module5 ==--
Public RELOADDBDATA As Boolean

'--== Module4 ==--
Public Enum RELOADDBDATA
    Dummy
End Enum

'--== Module3 ==--
Private Type RELOADDBDATA
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub RELOADDBDATA()
End Sub

'--== Module1 ==--
Public Function RELOADDBDATA() As Boolean
End Sub

Langkah 7:Tentukan properti kelas dengan nama yang sama

CATATAN:Ini semakin konyol.

'--== Class1 ==--
Private Property Get reloadDBData() As Boolean
End Property

'--== Module6 ==--
Private Const reloadDBData As Boolean = True

'--== Module5 ==--
Public reloadDBData As Boolean

'--== Module4 ==--
Public Enum reloadDBData
    Dummy
End Enum

'--== Module3 ==--
Private Type reloadDBData
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub reloadDBData()
End Sub

'--== Module1 ==--
Public Function reloadDBData() As Boolean
End Sub

Enum Item?!?!

Untuk poin ketiga ini, penting untuk membedakan antara tipe Enum dan item Enum .

Enum EnumTypeName   ' <-- Enum type
    EnumItemAlice   ' <-- Enum item
    EnumItemBob     ' <-- Enum item
End Enum

Kami telah menunjukkan di atas bahwa tipe Enum diperlakukan sama dengan jenis deklarasi lainnya, seperti subs, fungsi, konstanta, dan variabel. Setiap kali baris deklarasi untuk pengidentifikasi dengan nama itu diubah, setiap pengidentifikasi lain dalam proyek dengan nama yang sama memiliki casing yang diperbarui agar sesuai dengan perubahan terbaru.

Enum item khusus karena mereka adalah satu-satunya jenis pengidentifikasi yang casingnya dapat diubah kapan pun baris kode apa pun yang berisi nama item enum diubah.

Langkah 1. Tentukan dan isi Enum

'--== Module7 ==--
Public Enum EnumTypeName
    EnumItemAlice
    EnumItemBob
End Enum

Langkah 2. Lihat item Enum dalam kode

'--== Module8 ==--
Sub TestEnum()
    Debug.Print EnumItemALICE, EnumItemBOB
End Sub

Hasil:Deklarasi jenis enum berubah agar sesuai dengan baris kode biasa

'--== Module7 ==--
Public Enum EnumTypeName
    EnumItemALICE
    EnumItemBOB
End Enum

Bagian 2:Bagaimana kita bisa sampai di sini?

Saya belum pernah berbicara dengan siapa pun di tim pengembangan VBA internal. Saya belum pernah melihat dokumentasi resmi tentang mengapa VBA IDE bekerja seperti itu. Jadi, apa yang akan saya tulis adalah dugaan murni, tapi saya pikir itu masuk akal.

Untuk waktu yang lama, saya bertanya-tanya mengapa di dunia VBA IDE memiliki perilaku ini. Lagi pula, itu jelas disengaja. Hal termudah untuk dilakukan IDE adalah...tidak ada. Jika pengguna mendeklarasikan variabel dalam huruf besar semua, biarkan dalam huruf besar semua. Jika pengguna kemudian mereferensikan variabel tersebut dalam huruf kecil beberapa baris kemudian, biarkan referensi tersebut dalam huruf kecil dan deklarasi asli dalam huruf besar semua.

Ini akan menjadi implementasi bahasa VBA yang sangat dapat diterima. Lagi pula, bahasa itu sendiri tidak peka huruf besar-kecil. Jadi, mengapa bersusah payah untuk mengubah casing pengenal secara otomatis?

Cukup ironis, saya percaya motivasinya adalah untuk menghindari kebingungan. (Berayun dan meleset, jika Anda bertanya kepada saya.)  Saya mencemooh penjelasan ini, tetapi itu masuk akal.

Kontras dengan bahasa peka huruf besar-kecil

Pertama, mari kita bicara tentang programmer yang berasal dari bahasa yang peka huruf besar/kecil. Konvensi umum dalam bahasa peka huruf besar/kecil, seperti C#, adalah memberi nama objek kelas dengan huruf kapital dan memberi nama instance objek tersebut dengan nama yang sama dengan kelas, tetapi dengan huruf kecil di depan.

Konvensi itu tidak akan berfungsi di VBA, karena dua pengidentifikasi yang hanya berbeda dalam casing dianggap setara. Faktanya, Office VBA IDE tidak akan membiarkan Anda mendeklarasikan fungsi secara bersamaan dengan satu jenis casing dan variabel lokal dengan jenis casing yang berbeda (kami telah membahas ini secara mendalam di atas). Hal ini mencegah pengembang berasumsi bahwa ada perbedaan semantik antara dua pengenal dengan huruf yang sama tetapi huruf besar/huruf berbeda.

Membuat kode yang salah terlihat salah

Penjelasan yang lebih mungkin dalam pikiran saya adalah bahwa "fitur" ini ada untuk membuat pengidentifikasi yang setara terlihat identik. Pikirkan tentang itu; tanpa fitur ini, kesalahan ketik akan mudah berubah menjadi kesalahan runtime. Tidak percaya padaku? Pertimbangkan ini:

Private mAccountName As String
Private Const ACCOUNT_NAME As String = "New User"

Private Sub Class_Initialize()
    mAccountName = ACCOUNT_NAME
End Sub

Public Property Get MyAccountName() As String
    MAccountName = Account_Name
End Property

Public Property Let MyAccountName(AccountName As String)
    mAccountName = Account_Name
End Property

Jika Anda melihat sekilas kode di atas, itu terlihat cukup sederhana. Ini adalah kelas dengan .MyAccountName Properti. Variabel anggota untuk properti diinisialisasi ke nilai konstan ketika objek dibuat. Saat mengatur nama akun dalam kode, variabel anggota diperbarui lagi. Saat mengambil nilai properti, kode hanya mengembalikan konten variabel anggota.

Setidaknya, itulah yang seharusnya dilakukan. Jika saya menyalin kode di atas dan menempelkannya ke jendela VBA IDE, casing pengidentifikasi menjadi konsisten dan bug runtime tiba-tiba muncul dengan sendirinya:

Private mAccountName As String
Private Const ACCOUNT_NAME As String = "New User"

Private Sub Class_Initialize()
    mAccountName = ACCOUNT_NAME   ' <- This is OK
End Sub

Public Property Get MyAccountName() As String
    mAccountName = ACCOUNT_NAME   ' <- This is probably not what we intended
End Property

Public Property Let MyAccountName(AccountName As String)
    mAccountName = ACCOUNT_NAME   ' <- This is definitely not what we meant
End Property

Implementasi:Apakah ini benar-benar pendekatan terbaik?

Tidak. Jangan salah paham. Saya sebenarnya sangat menyukai gagasan untuk secara otomatis mengubah kapitalisasi pengidentifikasi untuk menjaga konsistensi. Satu-satunya keluhan saya adalah bahwa perubahan dibuat untuk setiap pengenal dengan nama itu di seluruh proyek. Jauh lebih baik untuk mengubah kapitalisasi hanya pengidentifikasi yang merujuk ke "benda" yang sama (apakah "benda" itu adalah fungsi, sub, properti, variabel, dll.).

Jadi mengapa tidak bekerja dengan cara ini? Saya berharap pengembang VBA IDE setuju dengan perspektif saya tentang cara kerjanya. Tapi, ada alasan yang sangat bagus mengapa IDE tidak bekerja seperti itu. Singkatnya, kinerja.

Sayangnya, hanya ada satu cara yang dapat diandalkan untuk menemukan pengidentifikasi dengan nama yang sama yang benar-benar merujuk ke hal yang sama:mengurai setiap baris kode. Itu sloooowwwwww. Ini lebih dari hipotesis sederhana di pihak saya. Proyek VBA Rubberduck sebenarnya melakukan hal ini; itu mem-parsing setiap baris kode dalam proyek sehingga dapat melakukan analisis kode otomatis dan banyak hal keren lainnya.

Proyek ini diakui kelas berat. Ini mungkin berfungsi dengan baik untuk proyek Excel. Sayangnya, saya tidak pernah cukup sabar untuk menggunakannya di salah satu proyek Access saya. Rubberduck VBA adalah proyek yang secara teknis mengesankan, tetapi juga merupakan kisah peringatan. Menghormati ruang lingkup saat mengubah kapitalisasi untuk pengidentifikasi akan menyenangkan untuk dimiliki, tetapi tidak dengan mengorbankan kinerja VBA IDE saat ini yang sangat cepat.

Pemikiran Terakhir

Saya memahami motivasi untuk fitur ini. Saya pikir saya bahkan mengerti mengapa itu diterapkan seperti itu. Tapi itu adalah satu-satunya kekhasan VBA yang paling menjengkelkan bagi saya.

Jika saya dapat membuat satu rekomendasi untuk tim pengembangan Office VBA, itu akan menawarkan pengaturan di IDE untuk menonaktifkan perubahan kasus otomatis. Perilaku saat ini dapat tetap diaktifkan secara default. Namun, bagi pengguna yang kuat yang mencoba berintegrasi dengan sistem kontrol versi, perilaku tersebut dapat dinonaktifkan sepenuhnya untuk mencegah "perubahan kode" yang mengganggu mengotori riwayat revisi.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana Profesional Real Estat Dapat Menggunakan Microsoft Access

  2. Industri Mana yang Paling Diuntungkan dari Akses?

  3. Bagaimana Access berbicara dengan sumber data ODBC? Bagian 1

  4. Transformasi Fungsionalitas Kelas Pembungkus

  5. Menggunakan Tampilan SQL untuk Menambahkan/Mengedit Data di Microsoft Access