Aynı ada sahip ad alanı ve sınıf?


102

Bir kütüphane projesi düzenliyorum ve adında bir merkezi yönetici sınıfım Scenegraphve Scenegraph ad alanında yaşayan bir sürü başka sınıfım var.

Gerçekten istediğim şey, senaryo olması MyLib.Scenegraphve diğer sınıfların olması MyLib.Scenegraph.*, ancak bunu yapmanın tek yolu, tüm diğer sınıfları ScenegraphScenegraph.cs dosyasındaki sınıfların iç sınıfları haline getirmek olabilir ve bu çok zahmetli .

Bunun yerine, hangi tür çalıştığını Mylib.Scenegraph.Scenegraphve olarak düzenledim MyLib.Scenegraph.*, ancak Visual Studio'nun sınıfa mı yoksa ad alanına mı atıfta bulunup bulunmadığım konusunda bazı koşullar altında kafasının karıştığını görüyorum.

Bu paketi düzenlemenin iyi bir yolu var mı, böylelikle kullanıcılar için tüm kodumu sürdürülemez bir karmaşa içinde bir araya getirmeden rahatlıkla kullanabilir miyim?

Yanıtlar:


112

Bir sınıfı kendi ad alanı gibi adlandırmanızı önermiyorum, bu makaleye bakın .

Çerçeve Tasarım Yönergeleri bölüm 3.4'te "bir ad alanı için aynı adı ve bu ad alanında bir tür kullanmayın" diyor. Yani:

namespace MyContainers.List 
{ 
    public class List { … } 
}

Bu neden kötülüktür? Oh, yolları saymama izin ver.

Kendinizi bir şeye atıfta bulunduğunuzu düşündüğünüz, ama aslında başka bir şeye atıfta bulunduğunuzu düşündüğünüz durumlara sokabilirsiniz. Bu talihsiz duruma düştüğünüzü varsayalım: Blah.DLL yazıyorsunuz ve ne yazık ki her ikisinin de Foo adlı bir türü olan Foo.DLL ve Bar.DLL dosyasını içe aktarıyorsunuz:

// 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; } 
}

Derleyici bir hata veriyor. "Foo", Foo.Foo ve Bar.Foo arasında belirsizdir. Bummer. Sanırım adı tam olarak nitelendirerek bunu düzelteceğim:

   class C { Foo.Foo foo; } 

Bu şimdi " Foo in Foo.Foo, Foo.Foo ve Bar.Foo arasında belirsiz " hatası veriyor . Hâlâ ilk Foo'nun neyi ifade ettiğini bilmiyoruz ve bunu çözene kadar ikincisinin neyi ifade ettiğini anlamaya bile zahmet etmiyoruz.


8
İlginç bir nokta. Hala üzerinde düşünmeye çalışıyorum. Teşekkürler. "Stil rehberi diyor" ile başlayan dürüst argümanlar beni etkilemiyor. Stil rehberlerinde çok fazla haksız saçmalık gördüm. Ama yukarıda iyi bir pratik tartışma yaparsınız. Zaten düşünmeye değer.
user430788

6
Yanıt "ne yapılmaması gerektiğini" söylüyor. Bazı yığın kullanıcıları "ne yapılacağını" ararken. Kimse Ant_222 cevabını önerir mi?
fantastory

3
Gerçekten sıkışmışsanız, ad alanınızın dışında yine de bir tür takma adı oluşturabilirsiniz. Harici takma adlar yalnızca iki tamamen aynı tam tanımlayıcınız (ad alanı + sınıf adı) olduğunda gereklidir.
Geoffrey

4
Yukarıdakilerin tümü güle güle ve fikirdir. Aslında çünkü bunu yapmak gerektiğidir C # derleyicisi bunu yanlış olacaktır oldukça net neler söylenmişti rağmen. Örneğin, using Foo.Bar;daha sonra Bar boldukça açık Barbir şekilde ad alanı içindeki bir sınıfa (veya numaralandırmaya) atıfta bulunulacaktır Foo.Bar. Bunu yapmamak için gerçek neden, tamamen C # derleyicisinin bunu doğru bir şekilde anlamamasıdır ki bu çok şaşırtıcı ve talihsiz bir durumdur. Başka herhangi bir şey yünlü stil tavsiyesidir.
TJ Crowder

2
Ben anlamadım Foo.Foo neden belirsizdir? Derleyiciye bu özel durumda Foo ad alanındaki Foo sınıfını kullanmak istediğinizi doğrudan söylersiniz. Hayır?
GuardianX

15

Ad alanına ve sınıfa aynı adın verilmesi, diğerlerinin söylediği gibi derleyicinin kafasını karıştırabilir.

O zaman nasıl adlandırılır?

Ad alanında birden çok sınıf varsa, tüm bu sınıfları tanımlayan bir ad bulun.

Eğer ad sadece bir sınıf vardır (dolayısıyla aynı adı verin günaha ve) ad ad SinifAdi NS . Microsoft en azından ad alanlarını böyle adlandırır.


6
Microsoft'tan böyle bir ad alanı örneğiniz var mı?
2018

@sunefred aradım ama bulamadım. Ama belgelerde gördüğümü kesinlikle hatırlıyorum. Bir isim alanında tek bir sınıfa sahip olmak istediğinizde pek çok durum yok sanırım.
GoTo

9

Sana bindi tavsiye izleyin öneririz microsoft.public.dotnet.languages.csharpkullanımına MyLib.ScenegraphUtil.Scenegraphve MyLib.ScenegraphUtil.*.



5

Sınıfınızı ad alanınızla aynı şekilde adlandırmamanız gerektiği konusunda diğer yanıtları kabul etsem de, bu tür gereksinimlere uyamayacağınız zamanlar vardır.

Örneğin benim durumumda, böyle bir kararı veren kişi ben değildim, bu yüzden bunun işe yaraması için bir yol bulmam gerekiyordu.

Dolayısıyla, ad alanı adını veya sınıf adını değiştiremeyenler için burada kodunuzu çalıştırmanın bir yolu var.

// 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
}

Temel olarak ad alanı "takma adları" oluşturdum ve bu, sınıfı tam olarak nitelendirmeme izin verdi ve Visual Studio "karışıklığı" ortadan kalktı.

NOT: Bunu yapmak sizin denetiminizdeyse, bu adlandırma çakışmasından kaçınmalısınız. Söz konusu tekniği yalnızca söz konusu sınıfların ve ad alanlarının kontrolü sizde olmadığında kullanmalısınız.


2
Kusursuz bir dünya için ilginç bir çözüm olduğu için oy verdim.
user430788

4

Sadece 2 sentimi eklemek:

Aşağıdaki sınıfa sahiptim:

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

Müşteri şöyle yazılmıştır:

using Foo;

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

GetFoo'nun çıktı parametresini kullanmak yerine çıktıyı döndürmemesini affeden, derleyici Foo.Bar [] veri türünü çözemedi. Hatayı döndürüyordu: Foo.Bar türü veya ad alanı bulunamadı.

Derlemeye çalıştığında, Foo'yu sınıf olarak çözdüğü ve Foo sınıfında gömülü bir Bar sınıfı bulamadığı anlaşılıyor. Ayrıca Foo.Bar adında bir ad alanı da bulamadı. Foo ad alanında bir Bar sınıfı arayamadı. Bir isim alanındaki noktalar sözdizimsel DEĞİLDİR. Tüm dize, noktalarla ayrılmış sözcükler değil, bir simgedir.

Bu davranış, .Net 4.6 çalıştıran VS 2015 tarafından sergilenmiştir.


3

Diğerlerinin de söylediği gibi, bir sınıfa kendi ad alanıyla aynı şekilde adlandırmaktan kaçınmak iyi bir uygulamadır.

İşte bazıları ek isimlendirme önerileri gelen svick tarafından bir cevap Yazılım Mühendisliği Stack Exchange'de "Aynı sınıf ve ad adı" ilgili soruya:

Ad alanını içerdiği türle aynı şekilde adlandırmamanız gerektiği konusunda haklısınız. Sanırım kullanabileceğiniz birkaç yaklaşım var:

  • Pluralize: Model.DataSources.DataSource

Bu, özellikle ad alanının birincil amacı aynı temel türden miras alan veya aynı arabirimi uygulayan türleri içermekse işe yarar.

  • Kısaltın: Model.QueryStorage

Bir ad alanı yalnızca az sayıda tür içeriyorsa, bu ad alanına hiç ihtiyacınız olmayabilir.

  • Enterprisey olun: Model.ProjectSystem.Project

Bu, özellikle ürününüzün önemli bir parçası olan özellikler için işe yarayabilir, bu nedenle kendi adlarını hak ederler.

(Not Yukarıdaki cevap kullanımları Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.ve Model.Project.Projectörneklerin, yerine MyLib.Scenegraph.Scenegraph).

(Buradaki diğer yanıtlardaki diğer adlandırma önerilerini de yararlı buldum.)


2

Eski gönderi, ama işte birine yardımcı olabilecek başka bir fikirle devam ediyorum:

"... ama bunu yapmanın tek yolu, tüm diğer sınıfları Scenegraph.cs dosyasındaki Scenegraph sınıfının iç sınıfları haline getirmek olabilir ve bu çok zahmetli."

Bu, bir dizi senaryo için gerçekten daha iyi bir uygulama. Ancak, tüm bu kodun aynı .cs dosyasında bulunmasının sinir bozucu olduğuna (en azından) katılıyorum.

Temel sınıfı bir "kısmi sınıf" yaparak çözebilir ve ardından kendi dosyalarında iç sınıfları oluşturmaya devam edebilirsiniz (sadece temel sınıf tamamlamasını bildirmeleri ve ardından belirli bir iç sınıfla devam etmeleri gerektiğini unutmayın. bu dosya için).

Gibi bir şey...

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

Bence bu, iç sınıfların temiz bir şekilde uygulanmasına daha yakın olurken, her şeyi tek bir büyük ve dağınık dosya içinde karıştırmak zorunda kalmazsınız.


2

Ad alanının ana sınıfı olduğunda olur. Yani isim alanını bir kitaplığa yerleştirmek bir motivasyondur, o zaman isim alanı adına 'Lib' eklerseniz sorun ortadan kalkar ...

namespace SocketLib
{
    class Socket
    {

Temiz çözüm. Gibi noktalar kullanıyordum Lib.Socketve sınıf adı aynı olduğunda sorunlarla karşılaştım. Artık daha az nokta kullanıyoruz.
57'de robsn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.