あなたはあまりにも多くの詳細を提供していないので、あなたが提供したものから回答しようとしています.
基本的な違いを見てみましょう: 基本
型Bと派生型Dがある場合、割り当ては次のようになります。
B my_B_object = my_D_object;
同じオブジェクトへの参照を割り当てます。一方、BとDが独立した型であり、それらの間で暗黙的な変換が行われる場合、上記の代入はのコピーを作成し、それ (またはがクラスのmy_D_object場合はそれへの参照) を に格納します。Bmy_B_object
要約すると、「実際の」継承は参照によって機能し (参照への変更は多くの参照によって共有されるオブジェクトに影響します)、カスタム型変換は一般に値によって機能します (実装方法によって異なりますが、「参照によって」に近いものを実装します)。 " コンバーターの動作はほとんど正気ではありません): 各参照は独自のオブジェクトを指します。
インターフェイスを使いたくないとおっしゃっていますが、なぜですか?コンボ インターフェイス + ヘルパー クラス + 拡張メソッド (C# 3.0 および .Net 3.5 以降が必要) を使用すると、実際の多重継承にかなり近づけることができます。これを見てください:
interface MyType { ... }
static class MyTypeHelper {
public static void MyMethod(this MyType value) {...}
}
「ベース」タイプごとにこれを行うと、必要なメソッドにデフォルトの実装を提供できます。
これらはそのままでは仮想メソッドとして動作しません。しかし、それを達成するためにリフレクションを使用することができます。Helper クラスの実装内から次のことを行う必要があります。
- で取得
System.Typeするvalue.GetType()
- その型に署名に一致するメソッドがあるかどうかを調べる
- 一致するメソッドが見つかった場合は、それを呼び出して戻ります (ヘルパーの残りのメソッドは実行されません)。
- 最後に、特定の実装が見つからない場合は、残りのメソッドを実行して、「基本クラスの実装」として機能させます。
C# の多重継承。ただし、これをサポートする基本クラスに醜いコードが必要になるという唯一の注意点と、リフレクションによるオーバーヘッドがあります。ただし、アプリケーションが大きなプレッシャーの下で動作していない限り、これでうまくいくはずです。
繰り返しになりますが、なぜインターフェースを使いたくないのでしょうか? メソッドの実装を提供できないことが唯一の理由である場合は、上記のトリックで解決できます。インターフェースに他の問題がある場合は、それらを整理しようとするかもしれませんが、最初にそれらについて知る必要があります;)
お役に立てれば。
[編集:コメントに基づく追加]
元の質問に詳細を追加しました。インターフェイスを使用したくないのは、ユーザーがインターフェイスを誤って実装したり、インジケーターを実装したい場合にオーバーライドする必要があるメソッド (つまり NewBar) を誤って呼び出したりして自分自身を撃ってしまうのを防ぎたいからです。直接呼び出す必要はありません。
私はあなたの更新された質問を見てきましたが、コメントはそれをかなり要約しています。多分私は何かが欠けているかもしれませんが、インターフェイス + 拡張機能 + リフレクションは、多重継承が可能なすべてを解決でき、タスクでの暗黙的な変換よりもはるかに優れています:
- 仮想メソッドの動作 (実装が提供され、継承者はオーバーライドできます): ヘルパーにメソッドを含めます (上記のリフレクション「仮想化」にラップされます)。インターフェイスで宣言しないでください。
- 抽象メソッドの動作 (実装は提供されず、継承者は実装する必要があります): インターフェイスでメソッドを宣言し、ヘルパーに含めないでください。
- 非仮想メソッドの動作 (実装が提供され、継承者は非表示にすることができますが、オーバーライドすることはできません): ヘルパーで通常どおり実装するだけです。
- ボーナス: 奇妙なメソッド (実装が提供されますが、継承者はとにかく実装する必要があります。基本実装を明示的に呼び出すことができます): 通常の継承または多重継承では実行できませんが、完全を期すために含めています:ヘルパーで実装を提供し、インターフェイスでも宣言します。それがどのように機能するか(仮想対非仮想の側面で)、またはそれがどのように使用されるかはわかりませんが、私のソリューションはすでに多重継承を打ち負かしています:P
注: 非仮想メソッドの場合、基本実装が確実に使用されるように、インターフェイスの型を「宣言された」型にする必要があります。これは、継承者がメソッドを非表示にする場合とまったく同じです。
ユーザーが誤って実装して足を撃たれるのを防ぎたい
ここでは、非仮想 (ヘルパーでのみ実装) が最適に機能するようです。
または、インジケーターを実装したい場合にオーバーライドする必要があるメソッド (つまり、NewBar) を誤って呼び出す
それが、抽象メソッド (または一種の超抽象的なものであるインターフェース) が最も輝くところです。継承者はメソッドを実装する必要があります。そうしないと、コードはコンパイルされません。場合によっては、仮想メソッドが適している場合があります (一般的な基本実装があるが、より具体的な実装が妥当な場合)。
ただし、直接呼び出す必要はありません
メソッド (またはその他のメンバー) がクライアント コードに公開されているが、クライアント コードから呼び出すべきではない場合、それを強制するプログラムによる解決策はありません (実際にはありますが、我慢してください)。ドキュメントに記載されている適切な場所に対処してください。APIを文書化しているからですよね?;) ここでは、変換も多重継承も役に立ちません。ただし、リフレクションが役立つ場合があります。
if(System.Reflection.Assembly.GetCallingAssembly()!=System.Reflection.Assembly.GetExecutingAssembly())
throw new Exception("Don't call me. Don't call me!. DON'T CALL ME!!!");
using System.Reflection;もちろん、ファイルにステートメントがある場合は、それを短くすることができます. そして、ところで、例外のタイプとメッセージをよりわかりやすいものに自由に変更してください;)。