Effective C# Item 30: Prefer CLS-Compliant Assemblies

來源:互聯網
上載者:User

Effective C# Item 30: Prefer CLS-Compliant Assemblies

      .Net環境是與語言無關的:開發人員可以不受限制的將各種不同的.Net語言編寫的組件結合起來。我們必須建立遵從於CLS(Common Language Specification)的程式集以便其他程式設計語言的開發人員可以使用我們的組件。

      CLS是每種語言必須支援的操作的子集。要建立一個符合CLS的程式集,我們必須將這個程式集的介面限制在符合CLS的範圍之內。這樣任何一種符合CLS的語言都可以使用這個程式集。不過這並不是要求我們在整個編程過程中都使用這些符合CLS的語言子集。

      要建立符合CLS的程式集,我們必須遵循兩條規則。首先所有公開和受保護的成員的參數和傳回值的類型必須是符合CLS的。其次,對於任何不符合CLS的公開或受保護的成員,必須有相當的符合 CLS 規範 的替換成員。

      第一個規則很容易達到。我們可以通過為程式集添加CLSCompliant屬性來強制編譯器進行檢測。

[assembly: CLSCompliantAttribute(true)]

      這樣編譯器會對整個程式集強制要求符合Common Language Specification。當我們的方法或屬性達不到要求時就會產生一個警告。這使得我們可以方便的達到目標。下面兩個例子不能通過要求,因為32位不帶正負號的整數是不符合CLS的。

public UInt32 Foo()
{
}

public void Foo2(UInt32 parm)
{
}

      我們應當明白建立符合CLS規範的程式集只會涉及到那些外部可見的成員。當Foo和Foo2被聲明為public或protected時會出現不符合CLS的警告。但是如果他們是private或internal的話,就可以包含在符合CLS規範的程式集內。CLS介面規範只要求那些暴露在外的程式集項目。

      下面的屬性是否符合CLS呢?

        public MyClass TheProperty
        {
            get
            {
                return _myClassVar;
            }
            set
            {
                _myClassVar = value;
            }
        }

      這要取決於MyClass是否符合CLS了。只有當MyClass符合CLS的情況下該屬性才符合CLS。

      當我們的公開和受保護的介面不符合CLS時,我們是不能建立符合CLS的程式集的。從組件設計的角度上來看,這使得我們的組件很難被那些希望建立符合CLS的程式集應用。他們必須將這些介面隱藏起來,建立相同功能性的封裝。雖然這是可行的,但是對於組件使用者來說並不是一個好的做法。我們應當在工作中盡量遵從CLS,對於那些需要建立符合CLS的程式集的使用者來說,這是最簡便的做法。

      第二個規則要求我們確保所有公開和受保護的操作都是和語言無關的。另外我們也需要確保沒有這種不符合的對象隱藏在應用了多態的介面中。

      操作符重載這個特性有的人喜歡,有的人討厭。並不是所有的語言都支援和允許操作符重載。CLS標準對於操作符重載的概念並沒有表示支援或者反對。它為每一個操作符定義了一個函數名稱:當我們使用=操作符時就建立了名為op_equals的函數。當我們重載了+運算子時就建立名為op_add的函數。當我們重載了運算子時,這些新的語義就可以在支援運算子多載的語言中使用了。對於那些使用不支援運算子多載的開發人員來說,他們必須使用“op_運算子函數”這樣的名稱。如果我們希望這些開發人員能使用我們的程式集,那麼我們就需要提供更加清晰的語義。這裡推薦一個比較簡單的方法:每當我們重載操作符,應當再建立一個相同功能的函數。

        public static Foo operator +(Foo left, Foo right)
        {
            return Foo.Add(left, right);
        }
 
        public static Foo Add(Foo left, Foo right)
        {
            return new Foo(left.Bar + right.Bar);
        }

      最後我們要注意在介面的多態中是否隱藏有不符合CLS的類型。這種情況比較容易出現在事件的參數中。我們可能會建立一個不符合CLS的類型並在使用其基類時要求其符合CLS。

      假設我們建立這這樣一個派生自EventArgs的類:

    internal class BadEventArgs : EventArgs
    {
        internal UInt32 ErrorCode;
    }

      這個BadEventArgs類是不符合CLS的。我們在其他語言中不能使用這樣的事件控制代碼。但是通過多態我們可以簡單的做到。我們可以聲明一個基類的事件類型EventArgs:

        public delegate void MyEventHandler(object sender, EventArgs args);
        public event MyEventHandler OnStuffHappens;

        BadEventArgs arg = new BadEventArgs();
        arg.ErrorCode = 24;
        OnStuffHappens(this, arg);

      在介面的聲明中,我們使用的是EventArgs參數,這是符合CLS的。但是實際上所用的類型卻是不符合的。這使得它在一些語言中無法使用。

      最後我們討論一下如何建立符合CLS的類和不符合的介面。這可能非常複雜,這裡我們簡單的介紹一下。瞭解符合CLS的幾口有助於我們全面理解CLS的含義以及運行環境是如何看待這種相容的。

      當我們為介面聲明為符合CLS時,它就是符合CLS的。

[assembly: CLSCompliantAttribute(true)]
public interface IFoo
{
    void DoStuff(Int32 arg1, string arg2);
}

      我們可以在任何符合CLS的類聲明中這樣的介面。然而,如果在沒有標記為符合CLS的程式集中聲明這樣的介面,它就不是符合CLS的。換句話說,只有定義在聲明為符合CLS的程式集中的介面才是符合CLS的。僅僅聲明介面是不足以達到目的的。這種情況是由於編譯器造成的。只有當程式集聲明符合CLS時,它才檢查每個類型是否符合CLS。在沒有聲明的時候,編譯器總是假設該程式集是不符合CLS的,其中的類,即便是該類聲明為CLS相容,也被認為是不符合CLS的。

      我們來看下面的這種情況:

public interface IFoo2
{
    void DoStuff(UInt32 arg1, string arg2);
}

      一個類公開的實現了不符合CLS的IFoo2介面。如果想要這個實現了IFoo2介面的類符合CLS,那麼我們必須使用介面的顯式實現。

public class MyClass : IFoo2
{
    void IFoo2.DoStuff(Int32 arg1, string arg2)
    {
    }
}

      MyClass擁有一個符合CLS的公開介面。期望使用IFoo2介面的用戶端必須通過不符合CLS的IFoo2來訪問它。

      但是這樣做還不夠。建立一個符合CLS的類型要求所有的公開和受保護介面只包含符合CLS的類型。這意味著我們的基類必須是符合CLS的。實現的所有介面也必須是符合CLS的。如果實現了一個非CLS的介面,那麼我們就必須使用明確介面實作來從公用介面中隱藏它。

      符合CLS並不是強制我們要採用最普遍的一般名稱來進行設計和實現。它要求我們關注程式集中的公用介面。對於任何公開或受保護的類來說,下面提到的幾項都應當是符合CLS的:

          1、 基類

          2、 公開和受保護的函數和屬性的傳回值

          3、 公開和受保護的函數和索引的參數

          4、 事件的參數

          5、 公用介面的聲明和實現

      我們只要多注意一些,就可以建立一個可以被其他語言使用的程式集了。CLS會確保語言的互動性。我們需要多花上一點時間在公用介面上。並不是代碼中所有的類型都必須是CLS的,只要避免那些不符合CLS的類出現在公用介面中就可以了。跨語言互通性值得我們花費這些時間。

      譯自   Effective C#:50 Specific Ways to Improve Your C#                      Bill Wagner著

      回到目錄
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.