「 using」指令應該在名稱空間以內仍是以外?

我一直在經過某些C#代碼運行StyleCop ,而且一直在報告個人using指令應該在名稱空間內。 函數

是否有技術上的理由將using指令放在名稱空間的內部而不是外部? ui


#1樓

將其放在名稱空間中會使聲明在文件的該名稱空間中處於本地狀態(若是文件中有多個名稱空間),可是若是每一個文件只有一個名稱空間,則它們在外部仍是外部都不會有太大的區別。在名稱空間中。 spa

using ThisNamespace.IsImported.InAllNamespaces.Here;

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

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

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

#2樓

根據Hanselman-使用指令和程序集加載...以及其餘此類文章,技術上沒有區別。 code

個人偏好是將它們放在名稱空間以外。 blog


#3樓

當您但願使用別名時,在名稱空間中放置using語句存在問題。 別名不能從較早的using語句中受益,必須徹底限定。 接口

考慮: ip

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

    class MyClass
    {
    }
}

與: 文檔

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

若是您有一個冗長的別名,例如如下內容(這就是我發現問題的方式),則這一點尤爲明顯: get

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

不漂亮。


#4樓

根據StyleCop文檔:

SA1200:在名稱空間中使用DirectivesMustBePlacedWith

緣由AC#using指令放置在名稱空間元素以外。

規則說明當將using指令或using-alias指令放置在名稱空間元素以外時,會發生違反此規則的狀況,除非文件不包含任何名稱空間元素。

例如,如下代碼將致使兩次違反此規則。

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類型。 若是將using指令移至名稱空間內,以下所示,則會發生編譯器錯誤:

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");的行中發現如下編譯器錯誤時失敗Guid g = new Guid("hello");

CS0576:命名空間「 Microsoft.Sample」包含與別名「 Guid」衝突的定義

該代碼建立System.Guid類型的別名Guid的別名,並使用匹配的構造函數接口建立本身的類型Guid的別名。 後來,代碼建立了Guid類型的實例。 要建立此實例,編譯器必須在Guid的兩個不一樣定義之間進行選擇。 當using-alias指令放置在namespace元素以外時,編譯器將選擇在本地命名空間內定義的Guid的本地定義,並徹底忽略在namespace以外定義的using-alias指令。 不幸的是,這在閱讀代碼時並不明顯。

可是,當using-alias指令位於名稱空間內時,編譯器必須在兩個不一樣的,衝突的Guid類型之間進行選擇,二者都在同一名稱空間內定義。 這兩種類型都提供了匹配的構造函數。 編譯器沒法作出決定,所以會標記編譯器錯誤。

將using-alias指令放置在名稱空間以外是一種很差的作法,由於在這種狀況下(實際上並不知道實際使用的是哪一個版本),這可能致使混亂。 這可能會致使可能難以診斷的錯誤。

在名稱空間元素中放置using-alias指令能夠消除這種狀況,使之成爲錯誤的來源。

  1. 多個命名空間

將多個名稱空間元素放在一個文件中一般是一個壞主意,可是若是這樣作,那麼最好將全部using指令放在每一個名稱空間元素中,而不是全局地放在文件頂部。 這將嚴格限制名稱空間的範圍,也將有助於避免上述行爲。

重要的是要注意,當使用放置在名稱空間以外的指令編寫代碼時,在將這些指令移至名稱空間內時應格外當心,以確保這不會改變代碼的語義。 如上所述,將using-alias指令放置在namespace元素中,可以使編譯器以衝突的方式進行選擇,方式是將指令放在命名空間以外時不會發生。

如何解決衝突要解決違反此規則的問題,請在命名空間元素內移動全部using指令和using-alias指令。


#5樓

二者之間實際上存在(細微)差別。 假設您在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成員,所以Outer.Math如今已損壞。

若是將using放在名稱空間聲明中,則狀況會發生變化,以下所示:

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

如今,編譯器在搜索Outer以前先搜索System而後找到System.Math ,一切都很好。

有人會認爲Math對於用戶定義的類來講多是個壞名字,由於System已經有一個了。 這裏要說的就是這樣有區別的,它會影響你的代碼的可維護性。

有趣的是,若是Foo在命名空間Outer而不是Outer.Inner ,會發生什麼。 在這種狀況下,不管using在何處,在Outer.Math中添加Outer.Math破壞Outer.Math 。 這意味着編譯器在查看任何using指令以前先搜索最裏面的命名空間。

相關文章
相關標籤/搜索