Soru 'Direktifleri kullanmak' ad alanının içinde mi yoksa dışında mı olmalıdır?


koşuyordum StyleCop Bazı C # kodları üzerinde using yönergeler ad alanının içinde olmalıdır.

Koymak için teknik bir neden var mı using ad alanı dışında direktifler içeriyor mu?


1741
2017-09-24 03:49


Menşei


Bazen bunları nereye koyduğunuzu fark eder: stackoverflow.com/questions/292535/linq-to-sql-designer-bug - gius
Sadece referans olarak, sadece dosya başına birden çok sınıf sorununun ötesinde imalar vardır, bu nedenle eğer bu soruya yeniyseniz, lütfen okumaya devam edin. - Charlie
@ user-12506 - orta düzeyde büyük geliştirme ekibinde, kod seviyesinin bir miktarının gerekli olduğu çok iyi çalışmaz. Daha önce de belirtildiği gibi, farklı düzenleri anlamıyorsanız, beklediğiniz gibi çalışmayan kenar durumları bulabilirsiniz. - benPearce
Terminoloji: Bunlar değil using  ifadeleri; onlar using  direktifler. bir using Öte yandan ifade, bir yöntem gövdesinin içindeki diğer ifadelerle birlikte ortaya çıkan bir dil yapısıdır. Örnek olarak, using (var e = s.GetEnumerator()) { /* ... */ } gevşek bir ifadedir var e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }. - Jeppe Stig Nielsen
Bu zaten kimsenin bahsetmemiş olsaydı, aslında Microsoft da koymayı önerir. using içindeki ifadeler namespace beyanları, onların iç kodlama kılavuzları - user1451111


Cevaplar:


Aslında ikisi arasında bir (ince) fark var. Aşağıdaki kodun File1.cs'de olduğunu düşünün:

// File1.cs
using System;
namespace Outer.Inner
{
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Şimdi, birinin buna benzeyen projeye başka bir dosya (File2.cs) eklediğini hayal edin:

// File2.cs
namespace Outer
{
    class Math
    {
    }
}

Derleyici arar Outer bunlara bakmadan önce using ad alanı dışındaki yönergeler, bu yüzden bulur Outer.Math yerine System.Math. Maalesef (ya da belki de neyse?), Outer.Math hayır PI üye, bu yüzden File1 şimdi bozuk.

Bu eğer koyursanız değişir using aşağıdaki gibi ad alanı bildirimi içinde:

// File1b.cs
namespace Outer.Inner
{
    using System;
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Şimdi derleyici arar System aramadan önce Outer, bulur System.Mathve her şey yolunda.

Bazıları bunu tartışırdı Math kullanıcı tanımlı bir sınıf için kötü bir isim olabilir, çünkü zaten bir tane var System; buradaki nokta oradaki olduğu Bir fark ve kodunuzun sürekliliğini etkiler.

Ayrıca ne olacağını not etmek ilginç Foo ad alanında Outer, ziyade Outer.Inner. Bu durumda ekleyerek Outer.Math File2 içinde nerede olursa olsun File1 keser using gider. Bu, derleyicinin, en içteki kapsayıcı ad alanını, herhangi bir şeye benzemeden önce aradığını gösterir. using direktif.


1844
2017-09-30 02:33



Bu, Mark'ın çok ad alanlı tek dosya argümanından yerel ifadeleri kullanmanın daha iyi bir nedenidir. Özellikle, derleme, adlandırma çakışmasından şikayetçi olabilir ve bu kural için StyleCop belgelerine (ör., Jared tarafından gönderilen) bakın. - David Schmitt
Kabul edilen cevap iyidir, ama bana göre kullanım şartlarını koymak için iyi bir sebep gibi görünüyor dışında ad alanı. Outer.Inner ad alanında iseniz, Math sınıfını Outer.Inner'dan değil System.Math'ten kullanmayı beklerdim. - Frank Wallis
Ben de buna katılıyorum. Kabul edilen cevap, teknik olarak farkı tarif etmesi açısından doğrudur. Bununla birlikte, bir veya diğer sınıfın açık bir belirtme çizgisine ihtiyacı olacaktır. Outer.Math önce System.Math "Math" olarak kullanılsa bile, kendi sınıfına "Math" çözümünün olması ve "System.Math" in dış sınıfa başvurması çok daha fazla olur. Evet, daha önceden var olan referansları düzeltmek için daha çok iş var, ama bu belki de Outer.Math'in farklı bir ismi olması gereken bir ipucu olabilir! - mbmcavoy
Harika bir cevap, ama bana öyle geliyor ki, sadece çerçeve olmayan ifadeleri yerel olarak kullanmak istiyorum ve çerçeveyi küresel ifadelerle kullanmaya devam ediyorum. Benim tercihimi neden tamamen değiştirmem gerektiğini daha fazla açıklama var mı? Ayrıca bu nereden geldi, VS2008'deki şablonlar ad alanının dışına çıktı mı? - Thymine
Bu, kullanım yerinizi değiştirmek yerine, daha çok kötü bir adlandırma kuralı olduğunu düşünüyorum. Çözümünüzde Matematik diye bir sınıf olmamalı. - jDeveloper


Bu iş parçacığının bazı harika yanıtları var, ancak bu ek cevapla biraz daha ayrıntı getirebileceğimi hissediyorum.

Öncelikle, bir isim alanı bildiriminin, aşağıdaki gibi dönemlerle olduğunu unutmayın:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

tamamen aynıdır:

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

Eğer istersen koyabilirsin using tüm bu seviyelerdeki direktifler. (Tabii ki sahip olmak istiyoruz usingsadece bir yerde, ama dile göre yasal olur.)

Hangi türün ima edildiğini çözme kuralı, aşağıdaki gibi gevşek bir şekilde ifade edilebilir: İlk olarak, bir eşleşme için iç en "kapsam" aramasını yapın, hiçbir şey bulunmazsa, bir sonraki kapsama bir seviye çıkar ve orada arama yapın, vb.Bir eşleşme bulunana kadar. Bir seviyede birden fazla eşleşme bulunursa, türlerden biri geçerli derlemeden geliyorsa, onu seçin ve bir derleyici uyarısı verin. Aksi halde pes et (derleme zamanı hatası).

Şimdi, bunun iki ana sözleşmeyle somut bir örnekte ne anlama geldiği konusunda açık olalım.

(1) dışında kullanımları ile:

using System;
using System.Collections.Generic;
using System.Linq;
//using MyCorp.TheProduct;  <-- uncommenting this would change nothing
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    class C
    {
        Ambiguous a;
    }
}

Yukarıdaki durumda, ne tür olduğunu öğrenmek için Ambiguous arama şu sırayla yapılır:

  1. İç içe türleri C (devralınan iç içe türler dahil)
  2. Geçerli ad alanındaki türler MyCorp.TheProduct.SomeModule.Utilities
  3. Ad alanındaki türler MyCorp.TheProduct.SomeModule
  4. Türleri MyCorp.TheProduct
  5. Türleri MyCorp
  6. Türleri boş ad alanı (genel ad alanı)
  7. Türleri System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, ve ThirdParty

Diğer kongre:

(2) içinde kullanımları ile:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using MyCorp.TheProduct;                           // MyCorp can be left out; this using is NOT redundant
    using MyCorp.TheProduct.OtherModule;               // MyCorp.TheProduct can be left out
    using MyCorp.TheProduct.OtherModule.Integration;   // MyCorp.TheProduct can be left out
    using ThirdParty;

    class C
    {
        Ambiguous a;
    }
}

Şimdi, türü arayın Ambiguous bu sırayla gider:

  1. İç içe türleri C (devralınan iç içe türler dahil)
  2. Geçerli ad alanındaki türler MyCorp.TheProduct.SomeModule.Utilities
  3. Türleri System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, ve ThirdParty
  4. Ad alanındaki türler MyCorp.TheProduct.SomeModule
  5. Türleri MyCorp
  6. Türleri boş ad alanı (genel ad alanı)

(Bunu not et MyCorp.TheProduct "3." nin bir parçasıydı. ve "4." arasında gerekli değildi. ve "5.".)

son sözler

Kullanımları ad alanı bildiriminin içine veya dışına çıkarırsanız, her zaman birisinin daha yüksek önceliğe sahip ad alanlarından birine aynı ada sahip yeni bir tür eklemesi olasılığı her zaman vardır.

Ayrıca, yuvalanmış bir ad alanı tür ile aynı ada sahipse, sorunlara neden olabilir.

Arama hiyerarşisi değiştiğinden ve başka bir tür bulunduğundan, kullanımı bir konumdan diğerine taşımak her zaman tehlikelidir. Bu nedenle, bir kongre seçin ve ona bağlı, böylece hiç bir zaman taşınmak zorunda kalmayacaksınız.

Visual Studio'nun şablonları varsayılan olarak kullanımı dışında ad alanının (örneğin, VS'nin yeni bir dosyada yeni bir sınıf oluşturmasını sağlarsanız).

Kullanmanın bir (küçük) avantajı dışında daha sonra, global bir öznitelik için kullanma direktiflerini kullanabilmeniz, örneğin [assembly: ComVisible(false)] yerine [assembly: System.Runtime.InteropServices.ComVisible(false)].


346
2018-04-18 21:00



teşekkürler, bu kabul edilen cevaptan çok daha iyi bir açıklamadır. - thor_hayek
Bu en iyi açıklamadır çünkü 'kullanma' ifadelerinin konumunun geliştiriciden kasıtlı bir karar olduğu gerçeğini vurgular. Hiçbir durumda, “anlam” ifadelerinin yerini, anlamlarını anlamadan dikkatsizce değiştirmemesi gerekir. Bu nedenle, StyleCop kuralı sadece aptaldır. - ZunTzu


Ad alanlarının içine koymak, bildirimleri dosya için bu ad alanına yerel hale getirir (dosyada birden fazla ad alanınız olması durumunda), ancak dosya başına yalnızca bir ad alanınız varsa, dışarı çıkıp çıkmamaları fark etmez. ad alanının içinde.

using ThisNamespace.IsImported.InAllNamespaces.Here;

namespace Namespace1
{ 
   using ThisNamespace.IsImported.InNamespace1.AndNamespace2;

   namespace Namespace2
   { 
      using ThisNamespace.IsImported.InJustNamespace2;
   }       
}

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

178
2017-09-24 03:52



ad alanları fiziksel (dosya) değil mantıksal bir ayrım sağlar. - Jowen
Hiçbir farkın olmadığı doğru değil; using içindeki direktifler namespace bloklar, çevrelemeye dayalı göreceli ad alanlarına başvurabilir namespace blok. - O. R. Mapper
Evet biliyorum. Bu sorunun beş yıl önce kabul ettiği cevabı belirledik. - Mark Cidade


Göre Hanselman - Direktif ve Montaj Yükleme Kullanımı ... ve bu tür diğer eşyaların teknik olarak hiçbir farkı yoktur.

Tercihim onları ad alanlarının dışına çıkarmak.


56
2017-09-24 03:53



@Chris M: uh ... cevapta yayınlanan link var yok hayır Karşılaştığınız bağlantıda yapılan iddiayı yanlış yönlendiren bir örnek göstererek, aslında dışarıda faydalanabilirsiniz ... - johnny
Evet, iş parçacığını tam olarak okumadım ama MVP'lerin doğru olduğunu söylediğinde aldım. Bir adam bunu onaylar, açıklar ve kodunu daha da aşağıya doğru gösterir ... "C # derleyicisinin ürettiği IL her iki durumda da aynıdır. Aslında C # derleyicisi, yönergeleri kullanan her şeyi tam olarak oluşturur. C # ism ve onlar için .NET'in bir anlamı yok. (İfadeleri kullanmak için doğru değil ama bunlar oldukça farklı.) groups.google.com/group/wpf-disciples/msg/781738deb0a15c46 - Chris McKee
Lütfen bağlantının bir özetini ekleyin. Ne zaman bağlantı bozuk (çünkü irade , yeterince zaman verilir,), 32 upvotes ile bir cevap aniden sadece değer My style is to put them outside the namespaces. - neredeyse hiç cevap yok. - ANeves
Buradaki iddia basitçe yanlış ... teknik bir fark var ve kendi alıntılarınız öyle diyor ki ... aslında, hepsi bu kadar. Lütfen bu yanlış cevabı silin ... çok daha iyi ve doğru olanlar var. - Jim Balter


StyleCop Belgesine Göre:

SA1200: UsingDirectivesMustBePlacedWithinNamespace

Sebeb olmak Bir C # yönergesi kullanılarak bir ad alanı öğesinin dışına yerleştirilir.

Kural Açıklaması Dosya, herhangi bir ad alanı öğesi içermedikçe, bir kullanım yönergesi veya bir takma ad yönergesi bir ad alanı öğesinin dışına yerleştirildiğinde, bu kuralın ihlali oluşur.

Örneğin, aşağıdaki kod bu kuralın iki ihlali ile sonuçlanır.

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

Ancak, aşağıdaki kod, bu kuralın ihlal edilmesine neden olmaz:

namespace Microsoft.Sample
{
    using System;
    using Guid = System.Guid;

    public class Program
    {
    }
}

Bu kod, derleyici hataları olmadan temiz bir şekilde derlenecektir. Bununla birlikte, Guid türünün hangi sürümünün tahsis edildiği belirsizdir. Kullanım yönergesi ad alanının içinde, aşağıda gösterildiği gibi hareket ettirilirse, bir derleyici hatası oluşacaktır:

namespace Microsoft.Sample
{
    using Guid = System.Guid;
    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

Kod, aşağıdaki satırı içeren, aşağıdaki derleyicide hata verir. Guid g = new Guid("hello"); 

CS0576: Ad alanı 'Microsoft.Sample', 'Guid' takma adıyla çakışan bir tanım içeriyor

Kod, Guid adlı System.Guid türünde bir takma ad oluşturur ve ayrıca, eşleşen bir kurucu arabirimiyle Guid adlı kendi türünü oluşturur. Daha sonra, kod Guid türünün bir örneğini oluşturur. Bu örneği oluşturmak için derleyicinin iki farklı Guid tanımını seçmesi gerekir. Using-alias yönergesi ad alanı elemanının dışına yerleştirildiğinde, derleyici yerel ad alanında tanımlanmış Guid'in yerel tanımını seçer ve ad alanının dışında tanımlanmış kullanma-takma yönergesini tamamen yok sayar. Bu maalesef kodu okurken açık değil.

Ancak, ad-alias yönergesi ad alanı içinde konumlandırıldığında, derleyici, her ikisi de aynı ad alanı içinde tanımlanan iki farklı, çakışan Guid türü arasında seçim yapmak zorundadır. Bu türlerin ikisi de eşleşen bir kurucu sağlar. Derleyici bir karar veremiyor, bu yüzden derleyici hatasını işaretler.

Ad-alan yönergesi ad alanının dışına yerleştirilmesi kötü bir uygulamadır çünkü bu tür durumlarda, hangi tür sürümün kullanılmakta olduğu açıkça görülemez. Bu, teşhis edilmesi zor olabilen bir hataya yol açabilir.

Ad alanı öğesi kullanılarak alias yönergeleri kullanılarak yerleştirme, bir hata kaynağı olarak bunu ortadan kaldırır.

  1. Birden çok İsim Alanı

Tek bir dosya içinde çok sayıda isim-alanı elemanının yerleştirilmesi genellikle kötü bir fikirdir, ancak bu yapıldığında, tüm yönergelerin tümünü, dosyanın en üstünde global olarak değil, tüm ad alanı öğelerinin içine yerleştirmek iyi bir fikirdir. Bu, ad alanlarını sıkıca kapsayacak ve ayrıca yukarıda açıklanan davranış türlerinden kaçınmanıza yardımcı olacaktır.

Kodun, ad alanının dışına yerleştirilen yönergeler kullanılarak yazıldığı durumlarda, bu yönergelerin ad alanı içinde taşınırken, kodun anlamını değiştirmediğinden emin olunması gerektiğine dikkat edilmelidir. Yukarıda açıklandığı gibi, isim-alanı yönergeleri ad alanı öğesi içine yerleştirmek, derleyicinin, yönergeler ad alanının dışına yerleştirildiğinde, çelişkili türler arasında seçim yapmamasını sağlar.

İhlalleri Düzeltme Bu kuralın ihlalini gidermek için, tüm yönergeleri ve ad alanı öğesi içindeki takma adlar'ı kullanarak tümünü taşıyın.


45
2017-09-14 15:17



@Jared - cevabımda belirttiğim gibi, tercih edilen geçici çözümüm / çözümüm, dosya başına yalnızca bir sınıfa sahip olmaktır. Bunun oldukça yaygın bir kongre olduğunu düşünüyorum. - benPearce
Gerçekten de bir StyleCop kuralı var! SA1402: Bir C # belgesi, tüm sınıflar kısmi ve aynı türden olmadıkça, yalnızca kök düzeyinde tek bir sınıf içerebilir. Başka bir kuralı sadece yanlış soslu damlamaları kırarak bir kural sergilemek. - Task
StyleCop perspektifi ile gerçek anlamda örtüşen ilk cevap olduğu için kışkırtıldı. Şahsen görsel hisleri severim usingad alanının dışında. İç usingBenim için çok çirkin görünüyor. :) - nawfal
Sonunda soruya iyi bir cevap. Ve benPearce'ın yorumu alakasız ... bunun dosyadaki sınıf sayısı ile ilgisi yok. - Jim Balter


Takma adları kullanmak istediğinizde ad alanı içinde ifadelerin kullanılmasıyla ilgili bir sorun var. Takma ad, daha önce yararlanamaz using ifadeler ve tamamen nitelikli olması gerekir.

Düşünmek:

namespace MyNamespace
{
    using System;
    using MyAlias = System.DateTime;

    class MyClass
    {
    }
}

e karşı:

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

Bu, özellikle aşağıdaki gibi uzun kenarlı bir takma adınız varsa (bu, sorunu nasıl buldum) açıklanabilir:

using MyAlias = Tuple<Expression<Func<DateTime, object>>, Expression<Func<TimeSpan, object>>>;

İle using ad alanı içindeki ifadeler, aniden olur:

using MyAlias = System.Tuple<System.Linq.Expressions.Expression<System.Func<System.DateTime, object>>, System.Linq.Expressions.Expression<System.Func<System.TimeSpan, object>>>;

Güzel değil.


29
2017-10-10 18:47



Sizin class bir isim (tanımlayıcı) gerektirir. Sahip olamazsın using belirttiğiniz gibi bir sınıf içinde yönerge. Bir isim alanı düzeyinde olmalı, örneğin en dışta namespaceya da sadece en içteki namespace (ama bir sınıf / arayüz / vb. içinde değil). - Jeppe Stig Nielsen
@JeppeStigNielsen Teşekkürler. Yanlış yerleştirdim using direktifler yanlış. Nasıl olmasını istediğim için düzenledim. İşaret ettiğin için teşekkürler. Yine de mantık hala aynı. - Neo


Jeppe Stig Nielsen rolünde dedimBu iş parçacığı zaten çok büyük cevaplara sahipti, ama bu belirgin inceliğin de bahsetmeye değer olduğunu düşündüm.

using Ad alanları içinde belirtilen yönergeler, dışarıda belirtildiklerinde tam olarak kalifiye olmaları gerekmediği için daha kısa kod yapabilirler.

Aşağıdaki örnek, türleri nedeniyle çalışır Foo ve Bar her ikisi de aynı küresel ad alanında Outer.

Kod dosyasını düşün Foo.cs:

namespace Outer.Inner
{
    class Foo { }
}

Ve Bar.cs:

namespace Outer
{
    using Outer.Inner;

    class Bar
    {
        public Foo foo;
    }
}

Bu dış isim alanını ihmal edebilir using Direktif, kısaca:

namespace Outer
{
    using Inner;

    class Bar
    {
        public Foo foo;
    }
}

2
2017-09-17 10:32



Dış ad alanını ihmal edebileceğiniz doğrudur, ama yapmanız gerektiği anlamına gelmez. Bana göre, bu, yönergelerin (@ Neo'un cevabındaki gibi diğer adların dışında) ad alanının dışına çıkarılmasının, tam olarak nitelenen ad alanı adlarını zorlamak için neden başka bir argüman. - Keith Robertson


Teknik nedenler cevaplarda tartışılmakta ve sonuçta kişisel tercihlere geldiğine inanıyorum. büyük ve her ikisi için de tahakküm var. Visual Studio'nun oluşturma için varsayılan şablonu .csdosyalar kullan using ad alanlarının dışındaki yönergeler ör.

Kontrol etmek için bir stilcop ayarlayabilir using ekleyerek ad alanlarının dışındaki yönergeler stylecop.json Proje dosyasının kökünde aşağıdakileri içeren dosya:

{
  "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
    "orderingRules": {
      "usingDirectivesPlacement": "outsideNamespace"
    }
  }
}

Bu yapılandırma dosyasını çözüm düzeyinde oluşturabilir ve projelerinizi tüm projelerinizde paylaşabilmeniz için projelerinize 'Mevcut Bağlantı Dosyası' olarak ekleyebilirsiniz.


0
2018-06-03 12:38





Eğer daha iyi bir uygulama varsayılan i.e.Referanslar"Kaynak çözümünüzde kullanılan ad alanlarının dışında ve "yeni eklenen referans" iyi bir uygulamadır, onu ad alanının içine koymalısınız. Bu, hangi referansların eklendiğini ayırt etmektir.


-7
2017-10-14 21:30



Hayır, aslında bu kötü bir fikir. Yerel olarak kapsamlandırılan ve genel olarak, yeni eklendikleri veya eklenmedikleri yönergelerin kullanıldığı yönergelerin kapsamını genişletmemeniz gerekir. Bunun yerine, üstüne çıkması gereken BCL referansları hariç, bunları alfabetik hale getirmek iyi bir uygulamadır. - Abel