29

誰でも次の動作を説明できますか?

要約すると、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 という 3 番目のライブラリを作成し、LibraryB を参照します (LibraryA は参照しません)。次のクラスを追加します。

namespace Ploeh.Samples.LibraryC
{
    public class Class1InLibraryC : Class2InLibraryB
    {
    }
}

これでもコンパイルできるはずです。Class1InLibraryC は、LibraryA の型を使用しないLibraryB のクラスから派生していることに注意してください。

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 準拠の間には奇妙な相互作用があるようです。

この問題は、上記のリストのオプションのいずれかを選択することで解決できますが、この動作の背後にある理由を説明できる人はいますか?

4

3 に答える 3

19

CLSの公式ドキュメント(http://msdn.microsoft.com/en-us/netframework/aa569283.aspx)を調べましたが、簡単な答えが見つかる前に頭が爆発しました。

しかし、基本は、コンパイラがLibraryCのCLS準拠を検証するために、LibraryAとの命名の競合の可能性を調査する必要があるということだと思います。

コンパイラーは、すべての「定義アセンブリの外部でアクセス可能または表示可能なタイプの部分」(CLSルール1)を検証する必要があります。

パブリッククラスClass1InLibraryCはClass2InLibraryBを継承するため、特に「Ploeh。*」がCLSルール5の「スコープ内」にあるため、LibraryAに対するCLS準拠も検証する必要があります。種類の」。

Class1InLibraryBまたはClass1InLibraryCの名前空間を変更して区別できるようにすると、名前が競合する可能性がなくなるようにコンパイラーに納得させるようです。

オプション(2)を選択し、参照を追加してコンパイルすると、結果のアセンブリメタデータで参照が実際にマークされていないことがわかります。したがって、これはコンパイル/検証時間の依存関係にすぎません。

于 2009-08-10T16:47:44.647 に答える
7

CLS は、生成されたアセンブリに適用される一連の規則であり、言語間の相互運用性をサポートするように設計されていることに注意してください。ある意味では、型が言語やプラットフォームにとらわれないようにするために従わなければならない規則の最小の共通サブセットを定義します。また、CLS 準拠は、定義アセンブリの外側に表示される項目にのみ適用されます。

CLS 準拠のコードが従うべきガイドラインのいくつかを見ると、次のようになります。

  • プログラミング言語でキーワードとして一般的に使用される名前の使用は避けてください。
  • フレームワークのユーザーがネストされた型を作成できるとは思わないでください。
  • 異なるインターフェース上の同じ名前と署名のメソッドの実装は独立していると仮定します。

CLS 準拠を決定するためのルールは次のとおりです。

  • アセンブリが明示的な System.CLSCompliantAttribute を持っていない場合、System.CLSCompliantAttribute(false) を持っていると見なされます。
  • 既定では、型はそれを囲む型の CLS 準拠属性を継承するか (入れ子になった型の場合)、そのアセンブリに関連付けられている準拠のレベルを取得します (最上位の型の場合)。
  • 既定では、他のメンバー (メソッド、フィールド、プロパティ、およびイベント) は、その型の CLS 準拠を継承します。

ここで、コンパイラに関する限り (CLS 規則 1)、アセンブリの外部にエクスポートされるすべての情報に CLS 準拠の規則を適用できなければならず、型がすべて公開されている場合、その型は CLS 準拠であると見なされます。アクセス可能なパーツ (別のアセンブリで実行されるコードで使用できるクラス、インターフェイス、メソッド、フィールド、プロパティ、およびイベント)

  • CLS 準拠の型のみで構成された署名を持っている、または
  • CLS に準拠していないと明示的にマークされています。

CTS ルールでは、スコープは単に名前のグループ/コレクションであり、スコープ内では、種類が異なる (メソッド、フィールド、ネストされた型、プロパティ、イベント) か、異なる署名を持つ限り、名前は複数のエンティティを参照できます。名前付きエンティティは、その名前が 1 つのスコープ内にあるため、そのエントリを識別するには、スコープと名前の両方を適用する必要があります。スコープは名前を修飾します。

型には名前が付けられているため、型の名前もスコープにグループ化されます。型を完全に識別するには、型名をスコープで修飾する必要があります。型名は、その型の実装を含むアセンブリによってスコープが設定されます。

CLS 準拠のスコープの場合、名前が同一でオーバーロードによって解決される場合を除き、すべての名前は種類に関係なく別個のものでなければなりません。つまり、CTS では単一の型がフィールドとメソッドに同じ名前を使用することを許可していますが、CLS では許可していません (CLS ルール 5)。

これをさらに一歩進めると、CLS 準拠の型は、CLS に準拠しない型の実装を要求してはならず (CLS 規則 20)、別の CLS 準拠の型からも継承する必要があります (CLS 規則 23)。

あるアセンブリのスコープ内の実装が、別のアセンブリにスコープされているか、別のアセンブリによって所有されているリソースを参照する場合、アセンブリは他のアセンブリに依存できます。

  • 他のアセンブリへのすべての参照は、現在のアセンブリ スコープの制御下で解決されます。
  • 特定の実装が実行されているアセンブリ スコープを特定することは常に可能です。そのアセンブリ スコープから発信されたすべての要求は、そのスコープに関連して解決されます。

これらすべてが最終的に意味することは、型の CLS 準拠を検証するために、コンパイラはその型のすべてのパブリック パーツも CLS 準拠であることを検証できなければならないということです。これは、名前がスコープ内で一意であること、独自の実装の一部が CLS に準拠していない型に依存していないこと、および CLS に準拠している他の型から継承されていることを確認する必要があることを意味します。これを行う唯一の方法は、型が参照するすべてのアセンブリを調べることです。

Visual Studio のビルド ステップは、基本的に MSBuild の実行に関する GUI ラッパーであり、最終的には C# コマンド ライン コンパイラを呼び出すためのスクリプト化された方法にすぎないことに注意してください。コンパイラが型の CLS 準拠を検証するには、(プロジェクトではなく) 参照するすべてのアセンブリを認識し、検出できる必要があります。これは MSBuild を介して呼び出され、最終的には Visual Studio を介して呼び出されるため、Visual Studio (MSBuild) がこれらのアセンブリを通知する唯一の方法は、それらを参照として含めることです。

明らかに、コンパイラは、CLS 準拠を検証して正常にコンパイルするために参照が「欠落している」ことを認識できるため、これらの参照を自動的に含めてくれればよかったのにと思います。ここでの問題は、含めるアセンブリのバージョンと、そのアセンブリがファイル システムのどこにあるかを判断することです。開発者にその情報を提供するように強制することで、コンパイラは正しい情報が提供されることを保証します。これには、ビルド中にすべての依存アセンブリが確実にまたはフォルダーにコピーされるという副作用もあります。これにより、アプリケーションがコンパイルされた後に実行されたときに、それらが正しいディレクトリに配置されます。Debug/binRelease/bin

于 2009-08-10T18:53:15.767 に答える
1

この問題は、Visual Studio 14 で使用できる Roslyn で修正されています。2014
年 7 月現在、現在の CTP はこちらから入手できます。
詳細については、このバグ レポートを参照してください。

于 2014-07-24T07:48:44.173 に答える