คำสั่ง 'ใช้' ควรอยู่ภายในหรือภายนอกเนมสเปซหรือไม่


2060

ฉันใช้งานStyleCopกับรหัส C # บางส่วนและมันยังคงรายงานว่าusingคำสั่งของฉันควรอยู่ในเนมสเปซ

มีเหตุผลทางเทคนิคในการวางusingคำสั่งในแทนที่จะเป็นนอก namespace หรือไม่?


4
บางครั้งมันสร้างความแตกต่างเมื่อคุณใส่การใช้งาน: stackoverflow.com/questions/292535/linq-to-sql-designer-bug
gius

82
สำหรับการอ้างอิงมีความหมายมากกว่าแค่คำถามหลาย ๆ คลาสต่อไฟล์ดังนั้นหากคุณยังใหม่กับคำถามนี้โปรดอ่านต่อไป
Charlie

3
@ user-12506 - มันทำงานได้ไม่ดีนักในทีมพัฒนาขนาดกลางถึงขนาดใหญ่ซึ่งจำเป็นต้องมีความสอดคล้องของรหัสบางระดับ และตามที่ระบุไว้ก่อนหน้านี้หากคุณไม่เข้าใจรูปแบบที่แตกต่างกันคุณอาจพบว่ามีกรณีขอบที่ไม่ได้ผลตามที่คุณคาดหวัง
benPearce

34
คำศัพท์: สิ่งเหล่านี้ไม่ใช่using ข้อความ ; พวกเขาจะมีคำสั่งusing usingคำสั่งบนมืออื่น ๆ ที่เป็นโครงสร้างภาษาที่เกิดขึ้นพร้อมกับงบอื่น ๆ ภายใน ฯลฯ วิธีร่างกายเป็นตัวอย่างที่เป็นคำสั่งที่เป็นอย่างอิสระเช่นเดียวกับusing (var e = s.GetEnumerator()) { /* ... */ } var e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
Jeppe Stig Nielsen

1
หากไม่ได้รับการกล่าวถึงโดยบุคคลอื่นจริง ๆ แล้ว Microsoft ก็แนะนำให้ใส่usingข้อความในnamespaceประกาศในguidlines การเข้ารหัสภายใน
user1451111

คำตอบ:


2132

ที่จริงแล้วมีความแตกต่าง (บอบบาง) ระหว่างสองคนนี้ ลองนึกภาพคุณมีรหัสต่อไปนี้ใน File1.cs:

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

ทีนี้ลองนึกภาพว่ามีคนเพิ่มไฟล์อื่น (File2.cs) ลงในโครงการที่มีลักษณะดังนี้:

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

การค้นหาที่คอมไพเลอร์Outerก่อนที่จะมองไปที่ผู้ที่usingสั่งนอก namespace จึงพบแทนOuter.Math System.Mathน่าเสียดายที่ (หรืออาจโชคดี) Outer.Mathไม่มีPIสมาชิกดังนั้น File1 จึงเสียหาย

การเปลี่ยนแปลงนี้หากคุณใส่การusingประกาศ namespace ของคุณภายในดังนี้:

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

ตอนนี้การค้นหาคอมไพเลอร์Systemก่อนที่จะค้นหาOuterพบSystem.Mathและทั้งหมดเป็นอย่างดี

บางคนอาจโต้แย้งว่าMathอาจเป็นชื่อที่ไม่ดีสำหรับคลาสที่ผู้ใช้กำหนดเนื่องจากมีอยู่แล้วในSystemนั้น จุดที่นี่เป็นเพียงที่มีคือความแตกต่างและมันมีผลต่อการบำรุงรักษาของรหัสของคุณ

นอกจากนี้ยังสนใจที่จะทราบว่าเกิดอะไรขึ้นถ้าFooอยู่ใน namespace มากกว่าOuter Outer.Innerในกรณีนั้นการเพิ่มOuter.Mathใน File2 จะเป็นการแบ่ง File1 โดยไม่คำนึงถึงว่าusingจะไปที่ไหน นี่หมายความว่าคอมไพเลอร์ค้นหาส่วนท้ายสุดของเนมสเปซก่อนที่จะดูusingคำสั่งใด ๆ


28
นี่เป็นเหตุผลที่ดีกว่ามากที่จะใช้คำสั่งภายในเครื่องมากกว่าอาร์กิวเมนต์หลายเนมสเปซ - อิน - วัน - ไฟล์ โดยเฉพาะอย่างยิ่งการคอมไพล์สามารถและจะบ่นเกี่ยวกับการตั้งชื่อแคลช (ดูเอกสาร StyleCop สำหรับกฎนี้ (เช่นโพสต์โดย Jared))
David Schmitt

148
คำตอบที่ได้รับการยอมรับเป็นสิ่งที่ดี แต่สำหรับฉันมันดูเหมือนว่าเป็นเหตุผลที่ดีที่จะนำคำสั่งที่ใช้อยู่นอกเนมสเปซ ถ้าฉันอยู่ใน namespace Outer.Inner ฉันคาดหวังให้ใช้คลาส Math จาก Outer.Inner ไม่ใช่ System.Math
Frank Wallis

7
ฉันเห็นด้วยกับสิ่งนี้เช่นกัน คำตอบที่ยอมรับนั้นถูกต้องซึ่งอธิบายความแตกต่างทางเทคนิค อย่างไรก็ตามคลาสหนึ่งหรือคลาสอื่นจะต้องมีไฮไลต์ที่ชัดเจน ฉันจะ ratehr มากมี "คณิตศาสตร์" การแก้ปัญหาในระดับท้องถิ่นของฉันเองและ "System.Math" อ้างถึงชั้นนอก - แม้ว่า System.Math ถูกใช้เป็น "คณิตศาสตร์" ก่อน Outer.Math อยู่ ใช่มันทำงานได้มากขึ้นในการแก้ไขอย่างไรก็ตามการอ้างอิงที่มีอยู่แล้วจำนวนมาก แต่นั่นอาจเป็นคำใบ้ที่บางที Outer.Math ควรมีชื่ออื่น!
mbmcavoy

13
คำตอบที่ดี แต่สำหรับฉันแล้วฉันอยากจะใส่ non-framework โดยใช้คำสั่งในเครื่องและทำให้ framework นั้นใช้คำสั่ง global ใครมีคำอธิบายเพิ่มเติมว่าทำไมฉันควรเปลี่ยนการตั้งค่าของฉันอย่างสมบูรณ์? เทมเพลตใน VS2008 นั้นนำมาใช้นอกเนมสเปซด้วยที่ไหน?
Thymine

31
ฉันคิดว่านี่เป็นวิธีการตั้งชื่อที่ไม่ดีมากกว่าการเปลี่ยนสถานที่ที่คุณใช้ ไม่ควรมีชั้นเรียนที่เรียกว่าคณิตศาสตร์ในการแก้ปัญหาของคุณ
jDeveloper

454

กระทู้นี้มีคำตอบที่ดีอยู่แล้ว แต่ฉันรู้สึกว่าฉันสามารถนำรายละเอียดเพิ่มเติมเล็กน้อยมาพร้อมกับคำตอบเพิ่มเติมนี้ได้

ก่อนอื่นให้จำไว้ว่าการประกาศเนมสเปซที่มีเครื่องหมายมหัพภาคเช่น:

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

เทียบเท่ากับ:

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

หากคุณต้องการคุณสามารถกำหนดusingคำสั่งในทุกระดับเหล่านี้ (แน่นอนเราต้องการมีusingเพียงแห่งเดียว แต่มันจะถูกกฎหมายตามภาษา)

กฎสำหรับการแก้ไขประเภทที่บอกเป็นนัยสามารถระบุแบบนี้ได้อย่างอิสระก่อนอื่นให้ค้นหา "ขอบเขต" ด้านในสุดสำหรับการจับคู่หากไม่มีสิ่งใดพบออกไปหนึ่งระดับไปยังขอบเขตถัดไปและค้นหาที่นั่นเป็นต้น , จนกว่าจะพบการแข่งขัน หากพบในการแข่งขันมากกว่าหนึ่งระดับหากประเภทหนึ่งมาจากชุดประกอบปัจจุบันให้เลือกตัวเลือกนั้นแล้วออกคำเตือนคอมไพเลอร์ มิฉะนั้นยอมแพ้ (ข้อผิดพลาดในการคอมไพล์เวลา)

ตอนนี้เรามาพูดถึงความหมายของตัวอย่างที่เป็นรูปธรรมพร้อมกับอนุสัญญาสำคัญสองประการ

(1) กับการใช้นอก:

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

ในกรณีข้างต้นหากต้องการทราบว่าAmbiguousเป็นประเภทใดการค้นหาจะเรียงตามลำดับนี้:

  1. ประเภทซ้อนภายในC(รวมถึงประเภทซ้อนซ้อนที่สืบทอด)
  2. ประเภทในเนมสเปซปัจจุบัน MyCorp.TheProduct.SomeModule.Utilities
  3. ประเภทในเนมสเปซ MyCorp.TheProduct.SomeModule
  4. ประเภทใน MyCorp.TheProduct
  5. ประเภทใน MyCorp
  6. ประเภทในเนมสเปซnull (เนมสเปซส่วนกลาง)
  7. ประเภทในSystem, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.IntegrationและThirdParty

การประชุมอื่น ๆ :

(2) กับการใช้ภายใน:

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

ตอนนี้ค้นหาประเภทAmbiguousไปตามลำดับนี้:

  1. ประเภทซ้อนภายในC(รวมถึงประเภทซ้อนซ้อนที่สืบทอด)
  2. ประเภทในเนมสเปซปัจจุบัน MyCorp.TheProduct.SomeModule.Utilities
  3. ประเภทในSystem, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.IntegrationและThirdParty
  4. ประเภทในเนมสเปซ MyCorp.TheProduct.SomeModule
  5. ประเภทใน MyCorp
  6. ประเภทในเนมสเปซnull (เนมสเปซส่วนกลาง)

(โปรดทราบว่าMyCorp.TheProductเป็นส่วนหนึ่งของ "3. " และไม่จำเป็นต้องใช้ระหว่าง "4. " และ "5. ")

สรุปข้อสังเกต

ไม่ว่าคุณจะใส่การใช้งานภายในหรือภายนอกการประกาศเนมสเปซมันก็มีความเป็นไปได้ที่ใครบางคนจะเพิ่มประเภทใหม่ที่มีชื่อเหมือนกันในเนมสเปซที่มีลำดับความสำคัญสูงกว่าเสมอ

นอกจากนี้หากเนมสเปซที่ซ้อนกันมีชื่อเดียวกับประเภทก็สามารถทำให้เกิดปัญหาได้

เป็นอันตรายเสมอที่จะย้ายการใช้จากที่หนึ่งไปอีกที่หนึ่งเนื่องจากลำดับชั้นการค้นหาเปลี่ยนแปลงและอาจพบประเภทอื่น ดังนั้นเลือกหนึ่งอนุสัญญาและติดกับมันเพื่อที่คุณจะได้ไม่ต้องย้ายการใช้เลย

โดยค่าเริ่มต้นเทมเพลตของ Visual Studio จะนำการใช้งานภายนอก namespace (ตัวอย่างเช่นถ้าคุณทำให้ VS สร้างคลาสใหม่ในไฟล์ใหม่)

หนึ่ง (เล็ก ๆ ) ประโยชน์ของการมี usings นอกคือการที่คุณจะสามารถใช้ประโยชน์จากการใช้ directives สำหรับแอตทริบิวต์โลกอาทิแทน[assembly: ComVisible(false)][assembly: System.Runtime.InteropServices.ComVisible(false)]


46
นี่คือคำอธิบายที่ดีที่สุดเพราะมันเน้นข้อเท็จจริงที่ว่าตำแหน่งของข้อความ 'ใช้' เป็นการตัดสินใจโดยเจตนาจากผู้พัฒนา ไม่ว่าในกรณีใดบางคนควรเปลี่ยนตำแหน่งที่ตั้งของข้อความ 'ใช้' อย่างไม่ระมัดระวังโดยไม่เข้าใจความหมาย ดังนั้นกฎ StyleCop จึงเป็นเพียงแค่ใบ้
ZunTzu

194

การวางไว้ในเนมสเปซทำให้การประกาศในโลคัลสำหรับเนมสเปซนั้นสำหรับไฟล์ (ในกรณีที่คุณมีเนมสเปซหลายไฟล์) แต่ถ้าคุณมีเนมสเปซเดียวต่อไฟล์ ภายในเนมสเปซ

using ThisNamespace.IsImported.InAllNamespaces.Here;

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

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

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

เนมสเปซให้การแยกแบบลอจิคัลไม่ใช่แบบฟิสิคัล (ไฟล์)
Jowen

9
มันไม่เป็นความจริงเลยที่ไม่มีความแตกต่าง usingคำสั่งภายในnamespaceบล็อกสามารถอ้างถึงเนมสเปซที่สัมพันธ์กันตามnamespaceบล็อกที่ล้อมรอบ
หรือผู้ทำแผนที่

70
ใช่ฉันรู้. เรายอมรับว่าในคำตอบที่ได้รับการยอมรับของคำถามนี้เมื่อห้าปีที่แล้ว
Mark Cidade

59

อ้างอิงจากHanselman - การใช้คำสั่งและการโหลดประกอบ ...และบทความอื่น ๆ มีเทคนิคไม่แตกต่างกัน

การตั้งค่าของฉันคือการวางไว้นอกเนมสเปซ


3
@ Chris M: เอ่อ ... การเชื่อมโยงไปโพสต์ในคำตอบที่บ่งชี้ว่ามีไม่มีผลประโยชน์ในกับออกจริงแสดงตัวอย่างที่ลวงตาเรียกร้องที่ทำในลิงค์ที่คุณโพสต์ ...
จอห์นนี่

2
ใช่ฉันไม่ได้อ่านกระทู้ทั้งหมด แต่ซื้อมาเมื่อ MVP พูดถูกต้อง ชายคนหนึ่งหักล้างอธิบายและแสดงรหัสของเขาต่อไป ... "IL ที่คอมไพเลอร์ C # สร้างนั้นเหมือนกันไม่ว่าในกรณีใดในความเป็นจริงคอมไพเลอร์ C # สร้างไม่ตรงกับแต่ละคำสั่งโดยใช้คำสั่ง C # ลัทธิและพวกเขาไม่มีความหมายที่จะ .NET ตัวเอง (ไม่จริงสำหรับการใช้งบ แต่ผู้ที่มีบางสิ่งบางอย่างที่แตกต่างกันค่อนข้าง.)". groups.google.com/group/wpf-disciples/msg/781738deb0a15c46
คริสแมค

84
โปรดระบุข้อมูลสรุปของลิงก์ เมื่อลิงก์เสีย (เพราะจะเกิดขึ้นให้เวลาเพียงพอ) ทันใดนั้นคำตอบที่มี 32 upvotes นั้นคุ้มค่ามากMy style is to put them outside the namespaces.- แทบจะไม่ได้คำตอบเลย
ตอบของ

11
การอ้างสิทธิ์ที่นี่เป็นเรื่องผิดปกติ ... มีความแตกต่างทางเทคนิคและการอ้างอิงของคุณเองก็บอกว่า ... จริง ๆ แล้วนั่นคือทั้งหมดที่เกี่ยวกับ โปรดลบคำตอบที่เข้าใจผิดนี้ไป ... มีคำตอบที่ดีกว่าและถูกต้องมาก
Jim Balter

53

ตามเอกสาร StyleCop:

SA1200: UsingDirectivesMustBePlacedWithinNamespace

สาเหตุ AC # โดยใช้คำสั่งถูกวางไว้ด้านนอกขององค์ประกอบเนมสเปซ

กฎคำอธิบายการละเมิดกฎนี้เกิดขึ้นเมื่อใช้ directive หรือ direct-alias directive อยู่นอกองค์ประกอบ namespace ยกเว้นว่าไฟล์จะไม่มีองค์ประกอบ namespace ใด ๆ

ตัวอย่างเช่นรหัสต่อไปนี้จะส่งผลให้มีการละเมิดกฎนี้สองครั้ง

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

อย่างไรก็ตามรหัสต่อไปนี้จะไม่ส่งผลให้เกิดการละเมิดกฎนี้:

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

    public class Program
    {
    }
}

รหัสนี้จะรวบรวมอย่างหมดจดโดยไม่มีข้อผิดพลาดของคอมไพเลอร์ อย่างไรก็ตามมันไม่ชัดเจนว่า Guid type ใดที่กำลังถูกจัดสรร หากคำสั่งการใช้ถูกย้ายภายในเนมสเปซดังที่แสดงด้านล่างข้อผิดพลาดของคอมไพเลอร์จะเกิดขึ้น:

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");
        }
    }
}

รหัสล้มเหลวในข้อผิดพลาดคอมไพเลอร์ต่อไปนี้พบในบรรทัดที่มี Guid g = new Guid("hello");

CS0576: Namespace 'Microsoft.Sample' มีคำจำกัดความที่ขัดแย้งกับนามแฝง 'Guid'

รหัสสร้างนามแฝงกับชนิด System.Guid ที่เรียกว่า Guid และยังสร้างชนิดของตัวเองที่เรียกว่า Guid ด้วยอินเทอร์เฟซตัวสร้างที่ตรงกัน ต่อมารหัสจะสร้างอินสแตนซ์ของประเภท Guid ในการสร้างอินสแตนซ์นี้คอมไพเลอร์ต้องเลือกระหว่างคำจำกัดความที่แตกต่างกันสองคำของ Guid เมื่อคำสั่ง use-alias วางอยู่ด้านนอกขององค์ประกอบเนมสเปซคอมไพเลอร์จะเลือกนิยามโลคัลของ Guid ที่กำหนดไว้ภายในเนมสเปซท้องถิ่นและไม่สนใจคำสั่ง use-alias ที่กำหนดไว้ภายนอกเนมสเปซ โชคไม่ดีที่เห็นได้ชัดเมื่ออ่านรหัส

เมื่อคำสั่ง use-alias อยู่ในตำแหน่งภายในเนมสเปซคอมไพเลอร์จะต้องเลือกระหว่าง Guid ชนิดต่าง ๆ สองชนิดที่ขัดแย้งกันซึ่งกำหนดไว้ภายในเนมสเปซเดียวกัน ทั้งสองประเภทนี้ให้ตัวสร้างการจับคู่ คอมไพเลอร์ไม่สามารถตัดสินใจได้ดังนั้นจึงตั้งค่าสถานะข้อผิดพลาดของคอมไพเลอร์

การวาง direct-directive ไว้นอกเนมสเปซเป็นการฝึกฝนที่ไม่ดีเพราะมันอาจทำให้เกิดความสับสนในสถานการณ์เช่นนี้ซึ่งไม่เป็นที่แน่ชัดว่าเวอร์ชันของชนิดใดที่ใช้งานจริง สิ่งนี้อาจนำไปสู่ข้อผิดพลาดซึ่งอาจวินิจฉัยได้ยาก

การวางคำสั่งนามแฝงภายในองค์ประกอบเนมสเปซกำจัดสิ่งนี้เป็นแหล่งของข้อบกพร่อง

  1. หลายเนมสเปซ

การวางองค์ประกอบเนมสเปซหลายรายการภายในไฟล์เดียวโดยทั่วไปเป็นความคิดที่ไม่ดี แต่ถ้าและเมื่อทำเช่นนี้เป็นความคิดที่ดีที่จะวางคำสั่งทั้งหมดโดยใช้คำสั่งภายในแต่ละองค์ประกอบเนมสเปซแทนที่จะเป็นส่วนกลางที่ด้านบนของไฟล์ สิ่งนี้จะกำหนดขอบเขตเนมสเปซให้แน่นและจะช่วยหลีกเลี่ยงพฤติกรรมที่อธิบายไว้ข้างต้น

เป็นสิ่งสำคัญที่จะต้องทราบว่าเมื่อโค้ดถูกเขียนด้วยการใช้คำสั่งที่วางอยู่นอกเนมสเปซควรใช้ความระมัดระวังเมื่อย้ายคำสั่งเหล่านี้ภายในเนมสเปซเพื่อให้แน่ใจว่านี่จะไม่เปลี่ยนซีแมนทิกส์ของรหัส ตามที่อธิบายไว้ข้างต้นการวาง direct-นามแฝงไว้ในองค์ประกอบ namespace ทำให้คอมไพเลอร์สามารถเลือกระหว่างชนิดที่ขัดแย้งกันในรูปแบบที่จะไม่เกิดขึ้นเมื่อวางคำสั่งไว้นอกเนมสเปซ

วิธีแก้ไขการละเมิดในการแก้ไขการละเมิดกฎนี้ให้ย้ายทั้งหมดโดยใช้คำสั่งและการใช้นามแฝงภายในองค์ประกอบเนมสเปซ


1
@ Jared - ตามที่ฉันบันทึกไว้ในคำตอบการแก้ปัญหา / วิธีแก้ปัญหาที่ฉันต้องการคือมีหนึ่งคลาสต่อไฟล์เท่านั้น ฉันคิดว่านี่เป็นการประชุมที่ค่อนข้างธรรมดา
benPearce

24
ที่จริงแล้วมันก็เป็นกฎของ StyleCop! SA1402: เอกสาร AC # อาจมีคลาสเดียวที่ระดับรูตเว้นแต่ว่าคลาสทั้งหมดจะเป็นบางส่วนและเป็นประเภทเดียวกัน จัดแสดงกฎหนึ่งโดยการทำลายอีกเพียงหยดกับซอสผิด
ภารกิจ

6
เพิ่มขึ้นเพื่อเป็นคำตอบแรกที่ครอบคลุมจริง ๆ จากมุมมอง StyleCop ส่วนตัวฉันชอบความรู้สึกที่มองเห็นของusingนอก namespace ด้านในusingดูน่าเกลียดมากสำหรับฉัน :)
nawfal

2
ในที่สุดคำตอบที่ดีสำหรับคำถาม และความคิดเห็นของ benPearce นั้นไม่เกี่ยวข้อง ... นี่ไม่เกี่ยวกับจำนวนคลาสในไฟล์
Jim Balter

35

มีปัญหาในการวางโดยใช้คำสั่งภายในเนมสเปซเมื่อคุณต้องการใช้นามแฝง นามแฝงไม่ได้รับประโยชน์จากข้อความก่อนหน้านี้usingและจะต้องผ่านการรับรองโดยสมบูรณ์

พิจารณา:

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

    class MyClass
    {
    }
}

เมื่อเทียบกับ:

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

นี่อาจเด่นชัดเป็นพิเศษหากคุณมีนามแฝงที่ยืดยาวเช่นต่อไปนี้ (ซึ่งเป็นวิธีที่ฉันพบปัญหา):

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

ด้วยusingคำสั่งภายในเนมสเปซมันจะกลายเป็น:

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

ไม่สวย.


1
คุณclassต้องการชื่อ (ตัวระบุ) คุณไม่สามารถมีusingคำสั่งภายในชั้นเรียนตามที่คุณระบุ มันจะต้องอยู่ในระดับเนมสเปซเช่นนอกสุดnamespaceหรือเพียงภายในสุดnamespace(แต่ไม่ได้อยู่ในชั้น / อินเตอร์เฟซ / ฯลฯ )
Jeppe Stig Nielsen

@JeppeStigNielsen ขอบคุณ ฉันหายไปในusingทิศทางที่ผิดพลาด ฉันแก้ไขมันตามที่ตั้งใจไว้ ขอบคุณสำหรับการชี้ให้เห็น แม้ว่าการใช้เหตุผลยังคงเหมือนเดิม
นีโอ

4

ดังที่ Jeppe Stig Nielsen กล่าวว่ากระทู้นี้มีคำตอบที่ดีอยู่แล้ว แต่ฉันคิดว่าความละเอียดอ่อนที่ค่อนข้างชัดเจนนี้ก็คุ้มค่าที่จะพูดถึงเช่นกัน

using คำสั่งที่ระบุไว้ในเนมสเปซสามารถสร้างรหัสให้สั้นลงได้เนื่องจากพวกเขาไม่จำเป็นต้องผ่านการรับรองอย่างเต็มที่เมื่อพวกเขาถูกระบุไว้ด้านนอก

ตัวอย่างต่อไปนี้ทำงานเพราะประเภทFooและBarมีทั้งใน namespace Outerโลกเดียวกัน

สมมติว่าไฟล์รหัสFoo.cs :

namespace Outer.Inner
{
    class Foo { }
}

และBar.cs :

namespace Outer
{
    using Outer.Inner;

    class Bar
    {
        public Foo foo;
    }
}

ที่อาจละเว้น namespace ด้านนอกในusingคำสั่งสั้น:

namespace Outer
{
    using Inner;

    class Bar
    {
        public Foo foo;
    }
}

8
มันเป็นความจริงที่คุณ "อาจละเว้น namespace ด้านนอก" แต่ไม่ได้หมายความว่าคุณควร สำหรับฉันนี่เป็นอีกเหตุผลว่าทำไมการใช้คำสั่ง (นอกเหนือจากนามแฝงในคำตอบของ @ Neo) ควรอยู่นอกเนมสเปซเพื่อบังคับใช้ชื่อเนมสเปซที่ผ่านการรับรองโดยสมบูรณ์
Keith Robertson

4

มีริ้วรอยหนึ่งอันที่ฉันวิ่งเข้ามา

สมมติว่าคุณมีเนมสเปซเหล่านี้:

  • Something.Other
  • Parent.Something.Other

เมื่อคุณใช้using Something.Other นอกnamespace Parent. มันหมายถึงอันแรก (Something.Other)

อย่างไรก็ตามหากคุณใช้ภายในการประกาศเนมสเปซนั้นจะอ้างอิงถึงอันที่สอง (Parent.Something.Other)!

มีวิธีแก้ไขง่ายๆคือเพิ่มglobal::คำนำหน้า "": docs

namespace Parent
{
   using global::Something.Other;
   // etc
}

2

เหตุผลทางเทคนิคถูกกล่าวถึงในคำตอบและฉันคิดว่ามันเป็นไปตามความชอบส่วนตัวในท้ายที่สุดเนื่องจากความแตกต่างนั้นไม่ใหญ่และมีการแลกเปลี่ยนสำหรับทั้งคู่ แม่แบบเริ่มต้นของ Visual Studio สำหรับการสร้าง.csไฟล์ใช้usingคำสั่งนอกเนมสเปซเช่น

หนึ่งสามารถปรับ stylecop เพื่อตรวจสอบusingคำสั่งนอก namespaces ผ่านการเพิ่มstylecop.jsonไฟล์ในรากของไฟล์โครงการดังต่อไปนี้:

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

คุณสามารถสร้างไฟล์ปรับแต่งนี้ในระดับโซลูชันและเพิ่มลงในโครงการของคุณเป็น 'ไฟล์ลิงก์ที่มีอยู่' เพื่อแชร์การกำหนดค่าในโครงการทั้งหมดของคุณด้วย


2

ความละเอียดอ่อนอื่นที่ฉันไม่เชื่อว่าได้รับการคุ้มครองโดยคำตอบอื่น ๆ คือเมื่อคุณมีคลาสและ namespace ที่มีชื่อเดียวกัน

เมื่อคุณมีการนำเข้าภายในเนมสเปซแล้วมันจะหาชั้นเรียน หากการอิมพอร์ตอยู่นอกเนมสเปซการอิมพอร์ตจะถูกข้ามและคลาสและเนมสเปซต้องผ่านการรับรองโดยสมบูรณ์

//file1.cs
namespace Foo
{
    class Foo
    {
    }
}

//file2.cs
namespace ConsoleApp3
{
    using Foo;
    class Program
    {
        static void Main(string[] args)
        {
            //This will allow you to use the class
            Foo test = new Foo();
        }
    }
}

//file2.cs
using Foo; //Unused and redundant    
namespace Bar
{
    class Bar
    {
        Bar()
        {
            Foo.Foo test = new Foo.Foo();
            Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
        }
    }
}

-8

มันเป็นวิธีที่ดีกว่าถ้าผู้เริ่มต้นใช้คือ " การอ้างอิง " ที่ใช้ในโซลูชันต้นทางของคุณควรอยู่นอกเนมสเปซและที่เป็น"การอ้างอิงใหม่ที่เพิ่ม"เป็นแนวปฏิบัติที่ดีคือคุณควรใส่ไว้ในเนมสเปซ นี่คือการแยกความแตกต่างที่อ้างอิงเพิ่ม


6
ไม่จริงที่เป็นความคิดที่ไม่ดี คุณไม่ควรยึดตำแหน่งระหว่างขอบเขตในพื้นที่กับขอบเขตทั่วโลกของการใช้คำสั่งเนื่องจากข้อเท็จจริงว่ามีการเพิ่มหรือไม่ แต่เป็นวิธีปฏิบัติที่ดีในการเรียงตามตัวอักษรยกเว้นการอ้างอิง BCL ซึ่งควรอยู่ด้านบน
Abel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.