CLSCompliant(true) 拖入未使用的引用
誰能解釋以下行為?
總之,如果您在 Visual Studio 2008 中創建多個符合 CLS的庫並讓它們共享一個公共命名空間根,則引用另一個庫的庫將需要對該庫的引用的引用,即使它不使用它們。
這很難用一句話來解釋,但這裡有一些重現行為的步驟(密切注意命名空間):
創建一個名為 LibraryA 的庫並向該庫添加一個類:
namespace Ploeh { public abstract class Class1InLibraryA { } }
[assembly: CLSCompliant(true)]通過添加到 AssemblyInfo.cs確保庫符合 CLS 。創建另一個名為 LibraryB 的庫並引用 LibraryA。將以下類添加到 LibraryB:
namespace Ploeh.Samples { public class Class1InLibraryB : Class1InLibraryA { } }和
namespace Ploeh.Samples { public abstract class Class2InLibraryB { } }確保 LibraryB 也符合 CLS。
請注意,Class1InLibraryB 派生自 LibraryA 中的類型,而 Class2InLibraryB 不是。
現在創建名為 LibraryC 的第三個庫並引用 LibraryB(但不是 LibraryA)。添加以下類:
namespace Ploeh.Samples.LibraryC { public class Class1InLibraryC : Class2InLibraryB { } }這仍然應該編譯。請注意, Class1InLibraryC 派生自 LibraryB 中的類,該類不使用 LibraryA 中的任何類型。
另請注意,Class1InLibraryC 是在一個命名空間中定義的,該命名空間是 LibraryB 中定義的命名空間層次結構的一部分。
到目前為止,LibraryC 沒有對 LibraryA 的引用,並且由於它不使用 LibraryA 中的任何類型,因此解決方案可以編譯。
現在也使 LibraryC CLS 兼容。突然,解決方案不再編譯,給你這個錯誤資訊:
‘Ploeh.Class1InLibraryA’ 類型在未引用的程序集中定義。您必須添加對程序集“Ploeh,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的引用。
您可以通過以下方式之一再次編譯解決方案:
- 從 LibraryC 中刪除 CLS 合規性
- 添加對 LibraryA 的引用(儘管您不需要它)
- 更改 LibraryC 中的命名空間,使其不屬於 LibraryB 的命名空間層次結構(例如更改為 Fnaah.Samples.LibraryC)
- 更改 Class1InLibraryB 的命名空間(即 LibracyC 中未使用的命名空間),使其不在 LibraryC 的命名空間層次結構中(例如更改為 Ploeh.Samples.LibraryB)
名稱空間層次結構和 CLS 合規性之間似乎存在一些奇怪的相互作用。
可以通過選擇上面列表中的一個選項來解決這個問題,但是任何人都可以解釋這種行為背後的原因嗎?
我查看了 CLS 的官方文件 ( <http://msdn.microsoft.com/en-us/netframework/aa569283.aspx> ),但在我找到一個簡單的答案之前,我的腦袋就爆炸了。
但我認為基礎是編譯器為了驗證 LibraryC 的 CLS 合規性,需要調查可能與 LibraryA 的命名衝突。
編譯器必須驗證所有“在定義程序集之外可訪問或可見的類型的所有部分”(CLS 規則 1)。
由於公共類 Class1InLibraryC 繼承 Class2InLibraryB,因此它還必須驗證對 LibraryA 的 CLS 合規性,特別是因為“Ploeh.*”現在是“在範圍內”,適用於 CLS 規則 5“在符合 CLS 的範圍中引入的所有名稱都應是不同的獨立的種”。
更改 Class1InLibraryB 或 Class1InLibraryC 的命名空間以使它們變得不同似乎使編譯器不再有可能發生名稱衝突。
如果您選擇選項 (2),添加引用並編譯,您將看到該引用實際上並未在生成的程序集元數據中標記,因此這只是編譯/驗證時的依賴。