2010-12-14 6 views
7

私はちょうど今注目している奇妙な問題に出くわしました。.Net継承 - 自動従属参照動作の問題

あなたは3つのプロジェクト

**議論の後に編集NOTE **

プロジェクトLIBAと解決策を持っている場合 - ClassBの

を持っています - にClassA

namespace LibA 
{ 
    public class ClassA 
    { 
     public override string ToString() 
     { 
      return "The logic in class A!"; 
     } 
    } 
} 

プロジェクトLibBを持っています

using LibA; 

namespace LibB 
{ 
    public class ClassB 
    { 
     public ClassA a; 

     public ClassB() 
     { 
      a = new ClassA(); 
     } 

     public object Foo() 
     { 
      return a; 
     } 
    } 
} 

プロジェクトLibC - クラスCを持っています

あなたがこれをコンパイルした場合
using LibB; 

namespace LibC 
{ 
    public class ClassC 
    { 
     public ClassB b; 

     public ClassC() 
     { 
      b = new ClassB(); 
     } 

     public object Foo() 
     { 
      return b.Foo(); 
     } 
    } 
} 

最後にテストドライバー

using System; 
using LibC; 

namespace Shell 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ClassC c = new ClassC(); 
      Console.WriteLine(c.Foo()); 
     } 
    } 
} 

今、すべてが完璧に動作します。 LibCのバイナリフォルダの内容を調べると、LibAとLibBをプルする必要があるかどうかを判断するために依存関係のチェーンが自動的にロールオーバーされることがわかります。

ただし、クラスBをクラスAから継承するように変更する場合 このようコンパイルする

using LibA; 

namespace LibB 
{ 
    public class ClassB : ClassA 
    { 
     ClassA a; 
    } 
} 

試みとして、あなたはエラー

エラー2型「LibA.ClassA」が参照されていないアセンブリで定義されているを取得します。アセンブリ 'LibA、Version = 1.0.0.0、Culture = neutral、PublicKeyToken = null'への参照を追加する必要があります。

**元の質問には、**

は誰もが知っているか、なぜLIBAにClassA ClassBののメンバーを参照するのに十分なスマートです(それがMSBuildのか、Visual Studioのであるかどうか)が、それはに十分にスマートではありませんClassAがClassBの基本クラスである場合、参照LibA?

は、私はそれがnitpickyだけど、私は実際にいくつかの一貫性のある行動をお願い申し上げます

**これらの観察テストと改正質問**

私はいくつかは、「直接」または「間接的」として定義するものを聞いています参照。しかし、直接的には可視性のスコープだけではなく、継承と実際のタイプの使用のようです。

テストドライバは、LibA、LibB、およびLibCを解決して自動的に参照できるほどスマートです。

publicメンバーClassAでClassBが可視ですが、それだけではコンパイル/リンクエラーが発生しません。

デバッガは、テストドライバからClassAを確実に解決するので、正しいアセンブリがロードされていることが明らかです。

だから心に留めてください。私は今、 "直接"と "間接"のものをすべて手に入れました。

リンカ/コンパイラ/ IDEが少なくとも「直接」シナリオで参照されたライブラリの依存関係を自動的に参照しようとしないのはなぜですか?依存関係が存在することを知り、間接的なシナリオでそれらを参照することは、明らかにスマートです。

+0

興味深い.... +1 – RPM1984

+0

最も興味深いのは、以前のVB.NETの男として、これは私が理解できないものです。 VB.NETコンパイラは、プロジェクトの依存関係を連鎖させるほどスマートです。なぜC#コンパイラではないのですか? – Crono

答えて

0

私はそれがnitpickyだけど、私は 本当にそれは一貫性であるいくつかの一貫した 行動

をいただければ幸いです。直接使用するすべてのタイプを参照する必要があります。間接参照は透過的に解決されます。

+0

間接参照は何を検討していますか?クラスBの私の改訂版に見られるように、クラスAを直接参照しています – Min

+0

しかし、 'ClassC'は' ClassA'について知らないので、直接参照は必要ありません。 ( 'ClassA'は' ClassB'のプライベートフィールドなので 'ClassC'には見えません)。 – Femaref

4

これは一貫した動作です。最初のものは単純な参照、2番目は継承です。

アセンブリがコンパイルされ、クラスが別のアセンブリのクラスを継承する場合は、その参照を構築する必要があります。

LibBのみLibBはまだだろう、LibAが更新されて、それをやっている間ClassAが変更された場合(これは一貫性のないコードを生成するClassBのクラス定義でを追加され、それがLibAからすべてをコピーしない情報が含まれています古い情報を含む)。

だからLibCに継承されたクラス定義を使用するには、このようLibAへの直接参照が必要とされ、それを構築する(ClassA用)LibAからの情報とLibBClassB)の両方を必要とします。

この例では、異なるアセンブリのクラスへの参照はすべてプライベートなので、次のレベルのみが返されます(ClassCはそのクラスを直接使用しないためClassAを知る必要はありません)。 ClassAの使用がClassBである場合、ClassCClassAへの直接参照を持ち、そのクラス定義への直接参照も必要です(LibAからLibCへの参照)。

異なる形式では、これは継承の例でも同じです。 ClassCは、ClassAへの直接参照を持ち(の結果、ClassAから継承している)、完全なクラス定義を構築するには、宣言アセンブリへの参照が必要です(つまり、LibA)。

+0

私は情報を継承する必要がある理由を理解します。なぜLibAとLibBがメンバーで、なぜそれが継承されている場合にLibAとLibBを自動的にコピーしないのか、LibAとLibBの両方を自動的にコピーするのだろうかと疑問に思っています – Min

+0

参照の場合は 'LibB'は' LibA' (すべての場合において、参照されるクラスはプライベートフィールドなので、外部に公開されないので、クラスの使用はそれについて知る必要はないことに注意してください)。しかし、継承の場合、 'ClassB'はまだ' ClassC'のメンバですが、 'ClassB'は' ClassA'を継承します。したがって、 'ClassC'は' ClassA'についても知っている必要があります。 – Femaref

+0

このノートでは、ClassAをClassBのパブリック変数として公開しましたが、それでもLibCでLibAを自動的に参照しています。しかし、私がその公開変数で何かをしようとしたとき、LibCからLibAを明示的に参照するよう依頼しました。 – Min

0

最初のシナリオでは、はClassAです。したがって、実行時にコンパイル時にリソースは必要ありません。

はClassAを継承しているため、コンパイラは最終アセンブリを作成するためにその定義と情報を必要とします。

最初のシナリオでは、VisualStudio は、参照先のDLLを出力ディレクトリにコピーします。なぜなら、必要なことがわかっているからです。

第2のシナリオでは、VisualStudioはというプロジェクトへの参照を追加しません。、それはあなたの主な疑いです。私はそれがあなたのプロジェクトに邪魔されることによって問題を避けるためにそういう意味だと思います。しかし、私はちょうど推測している...