Saya telah menjalankan StyleCop pada beberapa kode C #, dan terus melaporkan bahwa using
arahan saya harus berada di dalam namespace.
Apakah ada alasan teknis untuk menempatkan using
arahan di dalam daripada di luar namespace?
c#
.net
namespaces
stylecop
code-organization
benPearce
sumber
sumber
using
pernyataan ; mereka adalahusing
arahan . Sebuahusing
pernyataan, di sisi lain, adalah struktur bahasa yang terjadi bersama dengan pernyataan lain dalam metode tubuh dll Sebagai contoh,using (var e = s.GetEnumerator()) { /* ... */ }
adalah pernyataan yang longgar sama denganvar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
pernyataan di dalamnamespace
deklarasi, di dalam panduan koding internalJawaban:
Sebenarnya ada perbedaan (halus) antara keduanya. Bayangkan Anda memiliki kode berikut di File1.cs:
Sekarang bayangkan seseorang menambahkan file lain (File2.cs) ke proyek yang terlihat seperti ini:
Kompiler mencari
Outer
sebelum melihatusing
arahan - arahan di luar namespace, jadi ia menemukanOuter.Math
bukanSystem.Math
. Sayangnya (atau mungkin untungnya?), TidakOuter.Math
memilikiPI
anggota, jadi File1 sekarang rusak.Ini berubah jika Anda meletakkan bagian
using
dalam deklarasi namespace Anda, sebagai berikut:Sekarang kompiler mencari
System
sebelum mencariOuter
, menemukanSystem.Math
, dan semuanya baik-baik saja.Beberapa orang akan berpendapat bahwa itu
Math
mungkin nama yang buruk untuk kelas yang ditentukan pengguna, karena sudah ada satu di dalamnyaSystem
; intinya di sini adalah hanya bahwa ada adalah perbedaan, dan itu mempengaruhi rawatan kode Anda.Menarik juga untuk dicatat apa yang terjadi jika
Foo
ada dalam namespaceOuter
, bukanOuter.Inner
. Dalam hal ini, menambahkanOuter.Math
File2 memecah File1 terlepas dari manausing
. Ini menyiratkan bahwa kompiler mencari namespace terlampir paling dalam sebelum melihatusing
arahan apa pun .sumber
Utas ini sudah memiliki beberapa jawaban yang bagus, tetapi saya merasa saya bisa membawa sedikit lebih detail dengan jawaban tambahan ini.
Pertama, ingat bahwa deklarasi namespace dengan titik, seperti:
sepenuhnya sama dengan:
Jika Anda mau, Anda bisa
using
mengarahkan semua level ini. (Tentu saja, kami ingin memilikiusing
hanya di satu tempat, tetapi akan sah menurut bahasa.)Aturan untuk menyelesaikan jenis yang tersirat, dapat secara longgar dinyatakan seperti ini: Pertama mencari "lingkup" paling dalam untuk kecocokan, jika tidak ada yang ditemukan, keluar satu tingkat ke ruang lingkup berikutnya dan cari di sana, dan seterusnya , sampai kecocokan ditemukan. Jika pada tingkat tertentu lebih dari satu kecocokan ditemukan, jika salah satu jenis berasal dari rakitan saat ini, pilih yang itu dan keluarkan peringatan kompiler. Jika tidak, menyerah (kesalahan waktu kompilasi).
Sekarang, mari kita menjadi eksplisit tentang apa artinya ini dalam contoh nyata dengan dua konvensi utama.
(1) Dengan usings luar:
Dalam kasus di atas, untuk mengetahui apa jenisnya
Ambiguous
, pencarian dilakukan dalam urutan ini:C
(termasuk jenis tersarang yang diwarisi)MyCorp.TheProduct.SomeModule.Utilities
MyCorp.TheProduct.SomeModule
MyCorp.TheProduct
MyCorp
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, danThirdParty
Konvensi lainnya:
(2) Dengan usings di dalam:
Sekarang, cari jenisnya
Ambiguous
dengan urutan ini:C
(termasuk jenis tersarang yang diwarisi)MyCorp.TheProduct.SomeModule.Utilities
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, danThirdParty
MyCorp.TheProduct.SomeModule
MyCorp
(Perhatikan bahwa
MyCorp.TheProduct
itu adalah bagian dari "3." dan karena itu tidak diperlukan antara "4." dan "5.".)Komentar penutup
Tidak masalah jika Anda menempatkan usings di dalam atau di luar deklarasi namespace, selalu ada kemungkinan bahwa seseorang nanti menambahkan tipe baru dengan nama yang identik ke salah satu ruang nama yang memiliki prioritas lebih tinggi.
Juga, jika namespace bersarang memiliki nama yang sama dengan tipe, itu dapat menyebabkan masalah.
Itu selalu berbahaya untuk memindahkan usings dari satu lokasi ke lokasi lain karena hirarki pencarian berubah, dan jenis lain dapat ditemukan. Karena itu, pilih satu konvensi dan patuhi itu, sehingga Anda tidak perlu pernah memindahkan usings.
Templat Visual Studio, secara default, menempatkan usings di luar namespace (misalnya jika Anda membuat VS menghasilkan kelas baru dalam file baru).
Satu (kecil) keuntungan memiliki usings di luar adalah bahwa Anda kemudian dapat menggunakan arahan penggunaan untuk atribut global, misalnya,
[assembly: ComVisible(false)]
bukan[assembly: System.Runtime.InteropServices.ComVisible(false)]
.sumber
Menempatkannya di dalam namespaces membuat deklarasi lokal ke namespace untuk file tersebut (jika Anda memiliki beberapa namespaces dalam file) tetapi jika Anda hanya memiliki satu namespace per file maka itu tidak membuat banyak perbedaan apakah mereka pergi ke luar atau di dalam namespace.
sumber
using
arahan dalamnamespace
blok dapat merujuk ke ruang nama relatif berdasarkannamespace
blok terlampir .Menurut Hanselman - Menggunakan Petunjuk dan Pemuatan Majelis ... dan artikel-artikel serupa lainnya secara teknis tidak ada perbedaan.
Preferensi saya adalah menempatkannya di luar ruang nama.
sumber
My style is to put them outside the namespaces.
- hampir tidak ada jawaban sama sekali.Menurut Dokumentasi StyleCop:
SA1200: MenggunakanDirectivesMustBePlacedWithinNamespace
Penyebab AC # menggunakan arahan ditempatkan di luar elemen namespace.
Deskripsi Aturan Pelanggaran aturan ini terjadi ketika arahan menggunakan atau arahan using-alias ditempatkan di luar elemen namespace, kecuali file tersebut tidak mengandung elemen namespace.
Misalnya, kode berikut akan menghasilkan dua pelanggaran aturan ini.
Namun, kode berikut tidak akan mengakibatkan pelanggaran apa pun terhadap aturan ini:
Kode ini akan dikompilasi dengan bersih, tanpa ada kesalahan kompiler. Namun, tidak jelas versi jenis Guid yang dialokasikan. Jika arahan penggunaan dipindahkan di dalam namespace, seperti yang ditunjukkan di bawah ini, kesalahan kompiler akan terjadi:
Kode gagal pada kesalahan kompilator berikut, ditemukan pada baris yang berisi
Guid g = new Guid("hello");
CS0576: Namespace 'Microsoft.Sample' berisi definisi yang bertentangan dengan alias 'Guid'
Kode tersebut membuat alias ke tipe System.Guid yang disebut Guid, dan juga membuat tipe sendiri yang disebut Guid dengan antarmuka konstruktor yang cocok. Kemudian, kode menciptakan turunan dari tipe Guid. Untuk membuat instance ini, kompiler harus memilih antara dua definisi Guid yang berbeda. Ketika directive alias menggunakan ditempatkan di luar elemen namespace, kompiler akan memilih definisi lokal Guid didefinisikan dalam namespace lokal, dan sepenuhnya mengabaikan directive alias menggunakan yang didefinisikan di luar namespace. Sayangnya, ini tidak jelas ketika membaca kode.
Ketika menggunakan-alias direktif diposisikan dalam namespace, kompiler harus memilih antara dua jenis Guid yang berbeda dan saling bertentangan, keduanya didefinisikan dalam namespace yang sama. Kedua tipe ini menyediakan konstruktor yang cocok. Kompiler tidak dapat membuat keputusan, sehingga menandai kesalahan kompiler.
Menempatkan menggunakan-alias direktif di luar namespace adalah praktik yang buruk karena dapat menyebabkan kebingungan dalam situasi seperti ini, di mana tidak jelas versi jenis mana yang benar-benar digunakan. Ini berpotensi menyebabkan bug yang mungkin sulit didiagnosis.
Menempatkan arahan-alias menggunakan dalam elemen namespace menghilangkan ini sebagai sumber bug.
Menempatkan banyak elemen namespace dalam satu file umumnya adalah ide yang buruk, tetapi jika dan ketika ini dilakukan, itu adalah ide yang baik untuk menempatkan semua menggunakan arahan dalam setiap elemen namespace, daripada secara global di bagian atas file. Ini akan membatasi ruang nama secara ketat, dan juga akan membantu menghindari jenis perilaku yang dijelaskan di atas.
Penting untuk dicatat bahwa ketika kode telah ditulis dengan menggunakan arahan yang ditempatkan di luar namespace, harus berhati-hati ketika memindahkan arahan ini di dalam namespace, untuk memastikan bahwa ini tidak mengubah semantik kode. Seperti dijelaskan di atas, menempatkan arahan-alias menggunakan di dalam elemen namespace memungkinkan kompiler untuk memilih antara tipe yang saling bertentangan dengan cara yang tidak akan terjadi ketika arahan ditempatkan di luar namespace.
Cara Memperbaiki Pelanggaran Untuk memperbaiki pelanggaran aturan ini, pindahkan semua menggunakan arahan dan arahan menggunakan-alias di dalam elemen namespace.
sumber
using
di luar namespace. Batinusing
terlihat begitu buruk bagiku. :)Ada masalah dengan menempatkan pernyataan menggunakan di dalam namespace ketika Anda ingin menggunakan alias. Alias tidak mendapat manfaat dari
using
pernyataan sebelumnya dan harus sepenuhnya memenuhi syarat.Mempertimbangkan:
melawan:
Ini dapat diucapkan secara khusus jika Anda memiliki alias bertele-tele seperti berikut ini (yang merupakan bagaimana saya menemukan masalah):
Dengan
using
pernyataan di dalam namespace, tiba-tiba menjadi:Tidak cantik.
sumber
class
membutuhkan nama (pengidentifikasi). Anda tidak dapat memilikiusing
arahan di dalam kelas seperti yang Anda tunjukkan. Itu harus di tingkat namespace, misalnya di luar terluarnamespace
, atau tepat di dalam terluarnamespace
(tetapi tidak di dalam kelas / antarmuka / dll.).using
arahan secara keliru. Saya telah mengeditnya sesuai dengan yang saya inginkan. Terima kasih telah menunjukkan. Alasannya masih sama.Sebagai Jeppe Stig Nielsen mengatakan , thread ini sudah memiliki jawaban yang besar, tapi saya pikir kehalusan agak jelas ini layak disebut juga.
using
arahan yang ditentukan di dalam ruang nama dapat membuat kode lebih pendek karena tidak perlu sepenuhnya memenuhi syarat seperti ketika mereka ditentukan di luar.Contoh berikut berfungsi karena tipe
Foo
danBar
keduanya di namespace global yang samaOuter
,.Anggap file kode Foo.cs :
Dan Bar.cs :
Itu bisa menghilangkan namespace luar dalam
using
direktif, singkatnya:sumber
Satu kerutan yang saya temui (yang tidak tercakup dalam jawaban lain):
Misalkan Anda memiliki ruang nama ini:
Saat Anda menggunakan di
using Something.Other
luar anamespace Parent
, itu mengacu pada yang pertama (Sesuatu. Lainnya).Namun jika Anda menggunakannya di dalam deklarasi namespace itu, itu merujuk pada yang kedua (Parent. Sesuatu. Lainnya)!
Ada solusi sederhana: tambahkan
global::
awalan " ": docssumber
Alasan teknis dibahas dalam jawaban dan saya pikir itu pada preferensi pribadi pada akhirnya karena perbedaannya tidak begitu besar dan ada pengorbanan untuk keduanya. Template default Visual Studio untuk membuat
.cs
file menggunakanusing
arahan di luar ruang nama misalnyaOrang dapat menyesuaikan stylecop untuk memeriksa
using
arahan di luar ruang nama melalui menambahkanstylecop.json
file di root file proyek dengan yang berikut:Anda dapat membuat file konfigurasi ini di tingkat solusi dan menambahkannya ke proyek Anda sebagai 'File Tautan yang Ada' untuk membagikan konfigurasi di semua proyek Anda juga.
sumber
Kehalusan lain yang saya tidak percaya telah tercakup oleh jawaban lain adalah ketika Anda memiliki kelas dan namespace dengan nama yang sama.
Ketika Anda memiliki impor di dalam namespace maka itu akan menemukan kelas. Jika impor di luar namespace maka impor akan diabaikan dan kelas dan namespace harus sepenuhnya memenuhi syarat.
sumber
Ini adalah praktik yang lebih baik jika standar yang digunakan yaitu " referensi " yang digunakan dalam solusi sumber Anda harus berada di luar ruang nama dan yang "baru ditambahkan referensi" adalah praktik yang baik adalah Anda harus meletakkannya di dalam namespace. Ini untuk membedakan referensi apa yang ditambahkan.
sumber