Namespace dan kelas dengan nama yang sama?

95

Saya mengatur proyek perpustakaan dan saya memiliki kelas manajer pusat bernama Scenegraphdan sejumlah besar kelas lain yang tinggal di namespace Scenegraph.

Apa yang benar-benar saya inginkan adalah untuk menjadi skenario MyLib.Scenegraphdan kelas lainnya MyLib.Scenegraph.*, tetapi tampaknya satu-satunya cara untuk melakukannya adalah dengan membuat semua kelas lain dalam kelas Scenegraphdalam file Scenegraph.cs dan itu terlalu berat .

Sebaliknya, saya telah mengaturnya sebagai Mylib.Scenegraph.Scenegraphdan MyLib.Scenegraph.*, jenis pekerjaan yang mana tetapi saya menemukan Visual Studio menjadi bingung dalam beberapa kondisi, apakah saya merujuk ke kelas atau namespace.

Adakah cara yang baik untuk mengatur paket ini sehingga nyaman bagi pengguna tanpa menyatukan semua kode saya dalam kekacauan yang tidak dapat diperbaiki?

pengguna430788
sumber

Jawaban:

111

Saya tidak menyarankan Anda untuk memberi nama kelas seperti namespace-nya, lihat ini .

Pedoman Desain Kerangka mengatakan di bagian 3.4 "jangan gunakan nama yang sama untuk namespace dan tipe di namespace itu". Itu adalah:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Mengapa kejahatan ini? Oh, biarkan aku menghitung caranya.

Anda bisa mendapatkan diri Anda dalam situasi di mana Anda pikir Anda mengacu pada satu hal tetapi sebenarnya mengacu pada sesuatu yang lain. Misalkan Anda berakhir dalam situasi yang tidak menguntungkan ini: Anda menulis Blah.DLL dan mengimpor Foo.DLL dan Bar.DLL, yang sayangnya, keduanya memiliki tipe yang disebut Foo:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

Kompiler memberikan kesalahan. "Foo" adalah ambigu antara Foo.Foo dan Bar.Foo. Kekecewaan. Saya kira saya akan memperbaikinya dengan sepenuhnya memenuhi syarat nama:

   class C { Foo.Foo foo; } 

Ini sekarang memberikan kesalahan ambiguitas “ Foo in Foo.Foo ambigu antara Foo.Foo dan Bar.Foo ”. Kami masih tidak tahu apa yang dimaksud dengan Foo pertama, dan sampai kami dapat mengetahuinya, kami bahkan tidak repot-repot mencoba mencari tahu apa yang dimaksud dengan yang kedua.

pinckerman.dll
sumber
6
Ini hal yang menarik. Aku masih memikirkannya. Terima kasih. Saya harus menjadi argumen jujur ​​yang dimulai dengan "Panduan gaya mengatakan" jangan membuat saya terkesan. Saya telah melihat banyak sekali omong kosong yang tidak bisa dibenarkan dalam panduan gaya. Tetapi Anda membuat argumen praktis yang bagus di atas. Layak untuk dipikirkan.
pengguna430788
5
Tanggapannya mengatakan "apa yang tidak boleh dilakukan". Sementara beberapa pengguna tumpukan mencari "apa yang harus dilakukan". Adakah yang akan merekomendasikan jawaban Ant_222?
Fantastory
3
Jika Anda benar-benar buntu, Anda masih dapat membuat alias tipe di luar namespace Anda. Alias ​​eksternal hanya diperlukan jika Anda memiliki dua pengenal lengkap yang benar-benar identik (namespace + nama kelas).
Geoffrey
4
Semua di atas adalah ucapan selamat tinggal dan pendapat. The Kenyataan adalah bahwa Anda tidak harus melakukannya karena C # compiler akan salah paham itu , meskipun diberitahu cukup jelas apa yang terjadi. Misalnya, using Foo.Bar;kemudian Bar bcukup jelas mengacu pada Bar, kelas (atau enum) di dalam namespace Foo.Bar. Alasan sebenarnya untuk tidak melakukannya adalah murni karena compiler C # gagal memahaminya dengan benar, yang sangat mengejutkan dan disayangkan. Ada lagi saran gaya wol.
TJ Crowder
2
Saya tidak mengerti. Mengapa Foo.Foo ambigu? Anda langsung mengatakan kepada compiler bahwa Anda ingin menggunakan kelas Foo dari namespace Foo dalam kasus khusus ini. Tidak?
GuardianX
14

Pemberian nama yang sama ke namespace dan kelas dapat membingungkan compiler seperti yang dikatakan orang lain.

Lalu bagaimana menamainya?

Jika namespace memiliki beberapa kelas, temukan nama yang mendefinisikan semua kelas itu.

Jika namespace hanya memiliki satu kelas (dan karena itu tergoda untuk memberinya nama yang sama) beri nama namespace ClassName NS . Ini adalah bagaimana Microsoft memberi nama pada namespace mereka setidaknya.

Pergi ke
sumber
4
Apakah Anda memiliki contoh namespace seperti itu dari Microsoft?
sunefred
Saya harus mencarinya dan kembali kepada Anda.
GoTo
@sunefred Saya mencarinya, tetapi tidak dapat menemukannya. Tapi saya pasti ingat pernah melihatnya di dokumentasi. Saya kira tidak banyak kasus ketika Anda ingin memiliki satu kelas dalam namespace.
PergiTo
9

Saya menyarankan agar Anda mengikuti saran yang saya microsoft.public.dotnet.languages.csharpgunakan MyLib.ScenegraphUtil.Scenegraphdan MyLib.ScenegraphUtil.*.

Ant_222
sumber
7

CA1724: Type Names Should Not Match Namespaces ...

Pada dasarnya, jika Anda mengikuti Analisis Kode untuk pengkodean yang tepat, aturan ini mengatakan untuk tidak melakukan apa yang Anda coba lakukan. Analisis Kode sangat berguna dalam membantu Anda menemukan potensi masalah.

myermian
sumber
4

Hanya Menambahkan 2 sen saya:

Saya memiliki kelas berikut:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

Klien ditulis seperti ini:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

Memaafkan kesalahan GetFoo yang tidak mengembalikan output daripada menggunakan parameter out, kompilator tidak dapat menyelesaikan tipe data Foo.Bar []. Itu mengembalikan kesalahan: tidak dapat menemukan jenis atau namespace Foo.Bar.

Tampaknya ketika mencoba untuk mengkompilasinya diselesaikan Foo sebagai kelas dan tidak menemukan Bilah kelas tertanam di kelas Foo. Itu juga tidak dapat menemukan namespace yang disebut Foo.Bar. Gagal mencari bar kelas di namespace Foo. Titik-titik di ruang nama BUKAN sintaksis. Seluruh string adalah token, bukan kata-kata yang dibatasi oleh titik.

Perilaku ini ditunjukkan oleh VS 2015 yang menjalankan .Net 4.6

Steve
sumber
4

Meskipun saya setuju dengan jawaban lain bahwa Anda tidak boleh memberi nama kelas Anda sama dengan namespace Anda ada kalanya Anda tidak dapat memenuhi persyaratan tersebut.

Dalam kasus saya misalnya, saya bukanlah orang yang membuat keputusan seperti itu, oleh karena itu saya perlu menemukan cara untuk membuatnya berhasil.

Jadi bagi mereka yang tidak dapat mengubah nama namespace atau nama kelas di sini adalah cara di mana Anda dapat membuat kode Anda berfungsi.

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

Pada dasarnya saya membuat namespace "alias" dan yang memungkinkan saya untuk sepenuhnya memenuhi syarat kelas dan "kebingungan" Visual Studio hilang.

CATATAN: Anda harus menghindari konflik penamaan ini jika dalam kendali Anda untuk melakukannya. Anda sebaiknya hanya menggunakan teknik yang disebutkan saat Anda tidak mengontrol kelas dan namespace yang dimaksud.

Jonathan Alfaro
sumber
2
Saya memilihnya karena itu adalah solusi yang menarik untuk dunia yang tidak sempurna.
pengguna430788
2

Posting lama, tapi di sini saya pergi dengan ide lain yang dapat membantu seseorang:

"... tapi tampaknya satu-satunya cara untuk melakukan itu adalah dengan membuat semua kelas dalam Scenegraph dalam file Scenegraph.cs dan itu terlalu berat."

Ini benar-benar implementasi yang lebih baik untuk sekumpulan skenario. Tapi, saya setuju bahwa memiliki semua kode itu pada file .cs yang sama mengganggu (untuk sedikitnya).

Anda dapat menyelesaikannya dengan membuat kelas dasar sebagai "kelas parsial" dan kemudian, terus membuat kelas dalam pada file mereka sendiri (ingatlah bahwa mereka harus mendeklarasikan pelengkap kelas dasar dan kemudian melanjutkan dengan kelas dalam tertentu untuk file itu).

Sesuatu seperti...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

Saya pikir ini adalah semakin dekat Anda bisa mendapatkan implementasi yang bersih dari kelas dalam sementara tidak harus mengacaukan semuanya di dalam satu file besar dan berantakan.

Marcelo Myara
sumber
2

Seperti yang dikatakan orang lain, merupakan praktik yang baik untuk menghindari penamaan kelas yang sama dengan namespace-nya.

Berikut adalah beberapa saran penamaan tambahan dari jawaban oleh svick untuk pertanyaan terkait "Nama kelas dan namespace yang sama" di Software Engineering Stack Exchange:

Anda benar bahwa Anda tidak boleh memberi nama namespace sama dengan jenis yang dikandungnya. Saya rasa ada beberapa pendekatan yang dapat Anda gunakan:

  • Menjaminkan: Model.DataSources.DataSource

Ini berfungsi dengan baik terutama jika tujuan utama namespace adalah berisi jenis yang mewarisi dari jenis dasar yang sama atau mengimplementasikan antarmuka yang sama.

  • Persingkat: Model.QueryStorage

Jika namespace hanya berisi sejumlah kecil jenis, mungkin Anda tidak memerlukan namespace itu sama sekali.

  • Jadikan bisnis: Model.ProjectSystem.Project

Ini dapat berfungsi terutama untuk fitur yang merupakan bagian penting dari produk Anda, sehingga fitur tersebut layak mendapatkan namanya sendiri.

(Perhatikan bahwa penggunaan jawaban di atas Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.dan Model.Project.Projectsebagai contoh daripadaMyLib.Scenegraph.Scenegraph .)

(Saya juga menemukan saran penamaan lain di jawaban lain di sini bermanfaat.)

nak
sumber
1

Itu terjadi ketika itu adalah kelas utama namespace. Jadi itu salah satu motivasi untuk meletakkan namespace di perpustakaan, lalu masalahnya hilang jika Anda menambahkan 'Lib' ke nama namespace ...

namespace SocketLib
{
    class Socket
    {
Paul Sumpner
sumber