實現 CLS 相容性的第二條規則取決於開發者自身:必須確保所有公用及受保護的作業都是語言無關的,同時也要保證所使用的多型介面中不隱藏不相容的物件。
運算子多載這項功能見仁見智,並非所有語言都支援。CLS 標準對此不表態度,而是為每個運算子定義了對應的函數名稱,例如 op_Equals 對應 ==,op_Addition 對應 +。支援運算子多載的語言可直接使用運算子語法;不支援的語言則必須呼叫這些 op_ 開頭的方法。
為了讓使用不支援運算子多載語言的開發者也能順利使用你的組件,建議在多載運算子時,同時提供等效的靜態方法:
// 多載加法運算子,慣用 C# 語法
public static Foo operator+(Foo left, Foo right)
{
// 重用 Add 方法的實作
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 因使用 UInt32(非 CLS 相容)而不符合標準。但若事件委派宣告為基類型 EventArgs:
// 隱藏非相容的事件參數
public delegate void MyEventHandler(object sender, EventArgs args);
public event MyEventHandler OnStuffHappens;
// 引發事件時
BadEventArgs arg = new BadEventArgs();
arg.ErrorCode = 24;
// 介面合法,但執行期型別不相容
OnStuffHappens(this, arg);
雖然介面宣告符合 CLS,但實際傳遞的型別卻不相容,導致某些語言無法使用該事件。
若介面定義於標記 [assembly: CLSCompliant(true)] 的組件中,且成員皆為 CLS 相容型別(如 Int32、string),則該介面即為 CLS 相容:
[assembly: CLSCompliant(true)]
public interface IFoo
{
void DoStuff(Int32 arg1, string arg2);
}
理解 CLS 與介面的相容規則,有助於完整掌握 CLS 相容性的含義,也能知道執行環境如何看待相容性。