- 題名: 異なるプロジェクト間で基底・派生クラス作成時、基底クラスが参照できない
- 日時: 2009/12/04 12:10:17
- ID: 25962
- この記事の返信元:
- (なし)
- この記事への返信:
- [25964] Re[1]: 異なるプロジェクト間で基底・派生クラス作成時、基底クラスが参照できない2009/12/04 12:31:15
- [25976] Re[1]: 異なるプロジェクト間で基底・派生クラス作成時、基底クラスが参照できない2009/12/04 15:59:28
- ツリーを表示
■No25973に返信(わんこさんの記事) ■No25967に返信(わんこさんの記事) > ただ、ということは、この手のクラスライブラリを使用する際、ユーザ(使い手側)は > 常に使用したいクラスの基底クラスを知っておいて、自作プロジェクトに参照追加 > しなくてはならないということになるのでしょうか.... > > 使いづらくなってしまいますね 普通、ツリー状に実装するので大して使いにくくはならないかと思います。 変な事すると循環参照の罠にかかるので注意する必要がありますしね。 管理するだけ(コード実装しない)のであれば、クラスではなくインターフェイスのが良いです。 --------------------------- ◇ 基本ライブラリ 名前空間 : ObjectLibrary.ObjectModel アセンブリ名 : base.dll Public Interface IBase Function GetStringBase() As String End Interface --------------------------- ◇ サブライブラリ1 名前空間 : ObjectLibrary アセンブリ名 : sub1.dll 参照 : base.dll Imports ObjectLibrary.ObjectModel Public Class Sub1 Implements IBase Public Overridable Function GetStringBase() As String Implements IBase.GetStringBase Return "Sub1" End Function End Class --------------------------- ◇ サブライブラリ2 名前空間 : ObjectLibrary アセンブリ名 : sub2.dll 参照 : base.dll Imports ObjectLibrary.ObjectModel Public Class Sub2 Implements IBase Public Function GetStringBase() As String Implements IBase.GetStringBase Return "Sub2" End Function End Class --------------------------- ◇ 最終利用 (コンソールプロジェクト) 参照 : base.dll, sub1.dll, sub2.dll Imports ObjectLibrary.ObjectModel Imports ObjectLibrary Sub Main() ' インターフェイスで変数を作成 Dim base As IBase = Nothing ' サブクラス1をキャスト base = New Sub1() Console.WriteLine(base.GetStringBase()) ' サブクラス2をキャスト base = New Sub2() Console.WriteLine(base.GetStringBase()) End Sub --------------------------- ちなみに… インターフェイスは複数実装できるので、複数のインターフェイスを掛け合わせて作ることもできます。 --------------------------- ◇ 基本ライブラリ ( に追加 ) 名前空間 : ObjectLibrary.ObjectModel アセンブリ名 : base.dll Public Interface IBase2 Function GetStringOverSub() As String End Interface --------------------------- ◇ サブライブラリ3 名前空間 : ObjectLibrary アセンブリ名 : sub3.dll 参照 : base.dll, sub1.dll Imports ObjectLibrary.ObjectModel ' 両方のインターフェイスを実装 Public Class Sub3 Implements IBase Implements IBase2 Public Function GetStringBase() As String Implements IBase.GetStringBase Return "Sub3" End Function Public Function GetStringOverSub() As String Implements IBase2.GetStringOverSub Return "OverSub3" End Function End Class ' サブクラス1にインターフェイスを追加実装 Public Class Sub4 Inherits Sub1 Implements IBase2 Public Overrides Function GetStringBase() As String Return "Sub4" End Function Public Function GetStringOverSub() As String Implements IBase2.GetStringOverSub Return "OverSub4" End Function End Class --------------------------- ◇ 最終利用 (コンソールプロジェクト) 参照 : base.dll, sub1.dll, sub2.dll, sub3.dll Imports ObjectLibrary.ObjectModel Imports ObjectLibrary Sub Main() ' 各サブクラスを WriteLineメソッドで表示する WriteLine(New Sub1()) WriteLine(New Sub2()) WriteLine(New Sub3()) WriteLine(New Sub4()) End Sub ' 表示用メソッド Sub WriteLine(ByVal base As IBase) ' IBase の GetStringBase メソッドを表示 Console.WriteLine(base.GetStringBase()) ' IBase2が実装されているか確認。されてなければ終了。 If (TypeOf base Is IBase2) = False Then Return ' IBase2 にキャストして GetStringOverSub メソッドを呼ぶ Console.WriteLine(DirectCast(base, IBase2).GetStringOverSub()) End Sub --------------------------- こんな事もできますよ。って例でした。 > .NET Framework自体もこのような構成になっているのではないかと思うんですが > どのように実装しているのかわかればな ガイドラインと構成は、MSDNに書いてあるので探してみるといいかも。 単純にコードを見たいのであれば、こちらへ。(英語) http://referencesource.microsoft.com/
追加です(笑 ほかのアセンブリのクラスを使う場合にはラッパークラスを作るのが有効です --------------------------- ◇ サブライブラリ4 名前空間 : ObjectLibrary アセンブリ名 : sub4.dll 参照 : base.dll Imports ObjectLibrary.ObjectModel Public Class Sub5 Implements IBase Implements IBase2 ' 普通のコンストラクタ Public Sub New() Me.New(Nothing) End Sub ' ラッピング元のインスタンスを指定したコンストラクタ Public Sub New(ByVal baseInstance As IBase) Me.baseInstance = baseInstance End Sub ' ラッピング元のインスタンス Private baseInstance As IBase Public Function GetStringBase() As String Implements IBase.GetStringBase If (Me.baseInstance Is Nothing) Then Return "Sub5" Return "Sub5 with " + Me.baseInstance.GetStringBase() End Function Public Function GetStringOverSub() As String Implements IBase2.GetStringOverSub If (Me.baseInstance Is Nothing Or (Not Me.baseInstance Is Nothing AndAlso (TypeOf Me.baseInstance Is IBase2) = False)) Then Return "OverSub5" Return "OverSub5 with " + DirectCast(Me.baseInstance, IBase2).GetStringOverSub() End Function End Class --------------------------- ◇ 最終利用 (コンソールプロジェクト) 参照 : base.dll, sub3.dll, sub4.dll Imports ObjectLibrary.ObjectModel Imports ObjectLibrary Sub Main() ' 各サブクラスを WriteLineメソッドで表示する WriteLine(New Sub5()) WriteLine(New Sub5(New Sub3())) WriteLine(New Sub5(New Sub4())) End Sub ' 表示用メソッド Sub WriteLine(ByVal base As IBase) ' IBase の GetStringBase メソッドを表示 Console.WriteLine(base.GetStringBase()) ' IBase2が実装されているか確認。されてなければ終了。 If (TypeOf base Is IBase2) = False Then Return ' IBase2 にキャストして GetStringOverSub メソッドを呼ぶ Console.WriteLine(DirectCast(base, IBase2).GetStringOverSub()) End Sub ---------------------------
2009/12/04(Fri) 16:41:56 編集(投稿者) 2009/12/04(Fri) 16:40:03 編集(投稿者) > ただ、ということは、この手のクラスライブラリを使用する際、ユーザ(使い手側)は > 常に使用したいクラスの基底クラスを知っておいて、自作プロジェクトに参照追加 > しなくてはならないということになるのでしょうか.... > > 使いづらくなってしまいますね それは仕方ないと思います。 ただし、「名前空間」−「アセンブリ」−「クラス」の関係をユーザーが意識できるよう 関連付けているなら、ユーザーもさほど混乱なくクラスを使用できると思います。 たとえば1例として現在携わっているシステムの場合。 ソリューションに以下のようにプロジェクトを設けてます。 ■まず「プロジェクト名=ネームスペース名」になるよう慎重に定義します。 xxxx.Tools.Controls 汎用カスタムコントロールを提供します。 xxxx.Tools.Database データベースとアクセス用の汎用クラスを提供します。 xxxx.Tools.Utility アプリケーション全体で使用される汎用的な機能を提供します。 xxxx.Business.Master マスタ参照・更新用の機能を提供します。 xxxx.Business.Map 地図コンポーネントを提供します。 xxxx.Business.Sales 販売業務の参照・更新用の機能を提供します。 ■そして xxxx.Tools.Controls には自作のカスタムコントロールを加えます。 // 拡張テキストボックス xxxx.Tools.Controls.ExTextBox // 拡張データグリッドビュー xxxx.Tools.Controls.ExDataGridView ■また xxxx.Tools.Database には ADO.NET を隠蔽したクラスを設けます。 // ADO.NET をカプセル化し、簡素化したインターフェイスを提供します。 xxxx.Tools.Database.DataFacade ■業務で使う地図機能は、xxxx.Business.Map 名前空間にまとめます。 // 配送ルートを表示する地図コントロールです。 xxxx.Business.Map.MapControl ■販売集計用の画面は当然以下のようになります。 // 販売集計用画面です。 xxxx.Business.Sales.SalesSummaryForm こんな具合に「名前空間」に対して「クラス」が明確な意図を持った配置がなされていれば ユーザーはどこに何があるのか、このクラスはどのアセンブリにあるのかが推測しやすくなります。 もちろん最初は存在が曖昧なクラスもありますし、どの名前空間においていいか悩むクラスも存在します。 その場合、リファクタリングを進めていく中にクラスの機能が絞れてきて 配置すべき名前空間が判ると同時に名前空間を移動したり、 状況によっては名前空間の新設や統廃合を行ったりしてます。 だから「名前」は極めて大事ですね。 クラスの名前を決めるだけで、半日悩んだりします。
分類:[.NET]