سؤال

لقد تم تشغيل StyleCop على بعض التعليمات البرمجية C#, ويبقى التقارير أن بلدي using توجيهات يجب أن يكون داخل مساحة الاسم.

هل هناك سبب فني لوضع using توجيهات في الداخل بدلا من الخارج مساحة الاسم?

هل كانت مفيدة؟

المحلول

هناك في الواقع (خفية) الفرق بين الاثنين.تخيل أن لديك التعليمات البرمجية التالية في 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 توجيهات خارج مساحة ، لذلك يجد Outer.Math بدلا من System.Math.لسوء الحظ (أو ربما لحسن الحظ؟), Outer.Math لا PI عضو حتى File1 الآن مكسورة.

هذه التغييرات إذا وضعت using داخل مساحة الإعلان على النحو التالي:

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

الآن المترجم البحث System قبل البحث Outer, ويرى System.Math, و كل شيء على ما يرام.

قد يجادل البعض بأن Math قد يكون سيئا اسم المستخدم-تعريف الطبقة ، لأن هناك بالفعل واحدة في System;النقطة هنا هي أن هناك فقط هو الفرق ويؤثر على الصيانة من التعليمات البرمجية الخاصة بك.

كما أنها مثيرة للاهتمام أن نلاحظ ماذا يحدث إذا Foo في مساحة الاسم Outer, بدلا من Outer.Inner.في هذه الحالة, إضافة Outer.Math في File2 فواصل File1 بغض النظر عن مكان using يذهب.وهذا يعني أن المترجم البحث الأعمق أرفق مساحة الاسم قبل أن يبدو في أي using التوجيه.

نصائح أخرى

هذا الموضوع بالفعل بعض الأجوبة, ولكن أشعر أنني يمكن أن تجلب المزيد من التفاصيل مع هذا الجواب.

أولا تذكر أن مساحة الإعلان مع فترات مثل:

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

هو تماما ما يعادل:

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

إذا كنت تريد أن تضع using توجيهات على كل مستوى من هذه المستويات.(بالطبع نحن نريد أن يكون usings في مكان واحد فقط, ولكن سيكون القانونية وفقا اللغة.)

سيادة لحل أي نوع هو ضمنية يمكن أن تكون فضفاضة ذكر مثل هذا: البحث الأولى الداخلي الأكثر "نطاق" للمباراة ، إذا ما وجدت هناك من الخروج مستوى واحد إلى التالي نطاق البحث هناك ، وهلم جرا, حتى يتم العثور على تطابق.إذا على مستوى أكثر من مباراة واحدة ، إذا كان أحد أنواع من الجمعية الحالية ، واختيار أن المسألة مترجم تحذير.وإلا التخلي (وقت التحويل البرمجي خطأ).

الآن, دعونا نكون صريحة حول ما يعنيه هذا في مثال ملموس مع اثنين من الاتفاقيات الرئيسية.

(1) مع usings الخارج:

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) مع usings الداخل:

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.".)

الملاحظات الختامية

لا يهم إذا كنت وضعت usings داخل أو خارج مساحة الإعلان ، هناك دائما احتمال أن شخصا في وقت لاحق يضيف نوع جديد متطابقة مع اسم واحد من الأسماء التي لها أولوية أعلى.

أيضا ، إذا كانت متداخلة مساحة الاسم نفس اسم نوع ، فإنه يمكن أن يسبب مشاكل.

هو دائما خطيرة نقل usings من مكان إلى آخر لأن البحث الهرمي التغييرات و نوع آخر قد تكون وجدت.لذلك اختيار واحد الاتفاقية والتمسك بها ، بحيث أنك لن تضطر إلى نقل usings.

Visual Studio قوالب بشكل افتراضي وضع usings خارج مساحة الاسم (على سبيل المثال إذا قمت بإجراء مقابل إنشاء فئة جديدة في ملف جديد).

واحدة (صغيرة) الاستفادة من وجود usings خارج هو أن ثم يمكنك الاستفادة من استخدام التوجيهات العالمية السمة ، على سبيل المثال [assembly: ComVisible(false)] بدلا من [assembly: System.Runtime.InteropServices.ComVisible(false)].

وضعه داخل مساحات يجعل الإعلانات المحلية إلى أن اسم الملف (في حالة لديك عدة مساحات في الملف) ولكن إذا كان لديك فقط مساحة واحدة لكل ملف ثم لا يجعل الكثير من الفرق سواء كانوا يذهبون خارج أو داخل مساحة الاسم.

using ThisNamespace.IsImported.InAllNamespaces.Here;

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

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

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

وفقا Hanselman - استخدام التوجيه الجمعية التحميل... وغيرها من مثل هذه المقالات ليس هناك من الناحية الفنية لا فرق.

هو تفضيل بلدي ووضعها خارج مساحات الأسماء.

وفقا إلى StyleCop الوثائق:

SA1200:UsingDirectivesMustBePlacedWithinnamespace

السبب C# باستخدام التوجيه يتم وضعها خارج مساحة اسم العنصر.

وصف القاعدة انتهاك هذه القاعدة يحدث عند استخدام التوجيه أو باستخدام مستعار التوجيه يتم وضعها خارج مساحة العنصر إلا إذا كان الملف لا يحتوي على أي مساحة العناصر.

على سبيل المثال التعليمات البرمجية التالية من شأنه أن يؤدي في اثنين من انتهاكات من هذه القاعدة.

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 هو المخصصة.إذا كان التوجيه باستخدام نقل داخل مساحة الاسم ، كما هو مبين أدناه, مترجم خطأ سوف تحدث:

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:مساحة 'Microsoft.نموذج يحتوي على تعريف متضاربة مع الاسم المستعار 'Guid'

رمز يخلق مستعار إلى النظام.Guid نوع يسمى Guid كما يخلق نوع خاص بها يسمى Guid مع مطابقة منشئ واجهة.في وقت لاحق من التعليمات البرمجية بإنشاء مثيل من نوع Guid.لإنشاء هذا المثال ، فإن المترجم يجب أن تختار بين اثنين من تعاريف مختلفة Guid.عند استخدام الاسم المستعار التوجيه يتم وضعها خارج مساحة العنصر, مترجم اختيار المحلية تعريف المعرف الفريد العمومي تحديد المحلي ضمن مساحة الاسم و تجاهل تماما باستخدام مستعار توجيهات محددة خارج مساحة الاسم.هذه للأسف ليست واضحة عند قراءة التعليمات البرمجية.

عند استخدام الاسم المستعار التوجيه المتمركزة داخل مساحة الاسم ، ومع ذلك ، فإن المترجم أن يختار بين اثنين مختلفة متضاربة Guid كل أنواع محددة داخل نفس مساحة الاسم.كل من هذه الأنواع توفر مطابقة منشئ.المترجم هو قادر على اتخاذ قرار ، لذلك الأعلام المترجم خطأ.

وضع استخدام الاسم المستعار التوجيه خارج مساحة ممارسة سيئة لأنه يمكن أن يؤدي إلى الارتباك في حالات مثل هذه ، حيث أنه ليس من الواضح أي إصدار من نوع قيد الاستخدام بالفعل.وهذا يمكن أن يؤدي إلى الخلل الذي قد يكون من الصعب تشخيص.

وضع استخدام الاسم المستعار توجيهات داخل مساحة اسم العنصر يلغي هذا مصدر الخلل.

  1. مساحات متعددة

وضع متعددة مساحة العناصر داخل ملف واحد عموما هو فكرة سيئة ، ولكن عندما يتم ذلك, انها فكرة جيدة لوضع كل استخدام التوجيهات في كل من مساحة العناصر ، وليس على مستوى العالم في أعلى الملف.هذا وسوف نطاق مساحات بإحكام ، و يساعد أيضا على تجنب هذا النوع من السلوك هو موضح أعلاه.

من المهم أن نلاحظ أنه عندما تم كتابتها باستخدام توجيهات وضعها خارج مساحة ينبغي الحرص عند نقل هذه التوجيهات داخل مساحة الاسم ، لضمان أن هذا لا تتغير دلالات الرمز.كما هو موضح أعلاه ، ووضع باستخدام مستعار توجيهات داخل مساحة اسم عنصر يسمح للمترجم أن يختار بين متضاربة في أنواع الطرق التي لن تحدث عندما توجيهات توضع خارج مساحة الاسم.

كيفية إصلاح الانتهاكات لإصلاح انتهاك هذه القاعدة ، نقل كافة باستخدام توجيهات باستخدام مستعار توجيهات داخل مساحة اسم العنصر.

هناك مشكلة مع وضع استخدام البيانات داخل مساحة الاسم عندما كنت ترغب في استخدام الأسماء المستعارة.الاسم المستعار لا تستفيد من وقت سابق 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>>>;

ليست جميلة.

كما " جيب " مولر نيلسن قال, هذا الموضوع بالفعل رائع إجابات, ولكن أعتقد أن هذا واضح دقة يستحق الذكر أيضا.

using توجيهات محددة داخل مساحات يمكن أن تجعل أقصر البرمجية حيث أنها لا تحتاج إلى أن تكون مؤهل تماما كما انهم عندما المحددة في الخارج.

المثال التالي يعمل لأن أنواع Foo و Bar على حد سواء في نفس مساحة الاسم ، Outer.

تفترض رمز الملف فو.cs:

namespace Outer.Inner
{
    class Foo { }
}

و بار.cs:

namespace Outer
{
    using Outer.Inner;

    class Bar
    {
        public Foo foo;
    }
}

التي قد تغفل الخارجي مساحة في using التوجيه قصيرة:

namespace Outer
{
    using Inner;

    class Bar
    {
        public Foo foo;
    }
}

واحد التجاعيد قابلت (لم تتم تغطيتها في إجابات أخرى):

افترض أن لديك هذه الأسماء:

  • شيء.أخرى
  • الأم.شيء.أخرى

عند استخدام using Something.Other خارج من namespace Parent, ، فإنه يشير إلى أول واحد (شيء.أخرى).

ومع ذلك إذا كنت تريد استخدامه داخل من أن مساحة الإعلان ، فإنه يشير إلى ثانية واحدة (الوالدين.شيء.أخرى)!

هناك حل بسيط:إضافة "global::"البادئة: مستندات

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

آخر دقة لا تصدق تم تغطيتها من قبل إجابات أخرى هو عندما يكون لديك فئة مساحة مع نفس الاسم.

عندما يكون لديك داخل استيراد مساحة الاسم بعد ذلك سوف تجد الطبقة.إذا كان استيراد خارج مساحة الاسم ثم استيراد سيتم تجاهل فئة مساحة الاسم يجب أن يكون مؤهل بشكل كامل.

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

الأسباب الفنية تناقش في الإجابات و أعتقد أنه يأتي إلى التفضيلات الشخصية في النهاية لأن الفرق ليس كبير وهناك ميزات وعيوب لكلا منهم.Visual Studio القالب الافتراضي لخلق .cs استخدام ملفات using توجيهات خارج مساحات مثلا

واحد يمكن ضبط stylecop للتحقق using توجيهات خارج مساحات من خلال إضافة stylecop.json الملف في جذر ملف المشروع بما يلي:

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

يمكنك إنشاء هذا الملف config في حل المستوى إضافة إلى المشاريع القائمة رابط الملف' للمشاركة في التكوين في جميع المشاريع الخاصة بك أيضا.

فمن الأفضل إذا كانت تلك الممارسة الافتراضي باستخدام أي"المراجع"المستخدمة في المصدر الخاص بك يجب أن يكون الحل من خارج مساحات وتلك التي هي الجديد "إضافة مرجع" هو ممارسة جيدة يجب عليك وضعها داخل مساحة الاسم.هذا هو التمييز بين ما المراجع التي يتم إضافتها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top