2009-04-16 26 views
3

私はクラスの束を生成するライブラリを使用しています。ベースクラスオブジェクトでサブクラスメソッドを呼び出すにはどうすればよいですか?

これらのクラスはすべて共通の基本クラスから継承しますが、その基本クラスはすべてのサブクラスに共通のメソッドを定義していません。例えば

SubClassA : BaseClass{ 
    void Add(ItemA item) {...} 
    ItemA CreateNewItem() {...} 
} 

SubClassB: BaseClass{ 
    void Add(ItemB item) {...} 
    ItemB CreateNewItem() {...} 
} 

残念ながら、ベースクラスは、これらのメソッドを持っていません。これは素晴らしいことだ:

BaseClass{ 
    // these aren't actually here, I'm just showing what's missing: 
    abstract void Add(ItemBaseClass item); // not present! 
    abstract ItemBaseClass CreateNewItem(); // not present! 
} 

私のA + Bのオブジェクトのための共通の基底クラスとItemオブジェクトのための共通の基底クラスがあるので、私はポリモーフィズムの素晴らしい世界の恩恵を受けることを望んでいました。

残念ながら、一般的なメソッドは実際には基本クラスには存在しないので、私はそれらを仮想的に呼び出すことはできません。たとえば、これは完全である:

BaseClass Obj; 
Obj = GetWorkUnit(); // could be SubClassA or SubClassB 

ItemBaseClass Item = Obj.CreateNewItem(); // Compile Fail: CreateNewItem() isn't in the base class 

Item.DoSomething(); 

Obj.Add(Item); // Compile Fail: Add(...) isn't in the base class 

明らかにキャスティングは機能するが、どのタイプのものが利益を否定するかを知る必要がある。

これらのメソッドを呼び出すにはどうすればよいですか?私は呼び出したいメソッドを実装していないオブジェクトを取得する心配はありません。

CType(Obj, Object).Add(Item) // Note: I'm using C#--NOT VB 

Againt、私は(私はルールアウト部分クラスを考えて)、これらのクラスを制御することはできません:私はインテリセンスを得ることはありませんが、コンパイラの幸せ、それが動作します - 私は実際にVBで私がやりたいことができます。

+0

あなた自身の方法には何が問題なのですか? Option Strictを有効にしている場合にのみ私を使用してください –

+0

サブクラスを管理できますか?もしそうなら、Luceroの解決策に進んでください。 –

+1

@Michael Haren:C#にはOption Strictがまったくありません。私のソリューションは、クラスを制御できない場合に機能します.Lucceroのソリューションは、サブクラスを制御できる場合に最適です。 –

答えて

6

リフレクションやその他の汚いトリックに頼らなくても、派生クラスの非仮想メソッドを呼び出すことはできません。あなたがそれをしたい場合は、それはその後、簡単です:

// obj is your object reference. 
obj.GetType().InvokeMember("MethodName", 
    System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */) 
+1

汚いトリックを使っても構いません! VBが喜んでそれを受け入れるなら、それは夢中ではありません...まあまあですが、私は見たいと思っています... –

+0

なぜ反射が汚いですか? :) 今日はかなり普遍的ですし、あなたは反射なしでコードに等しく機能させることさえできます。 – majkinetor

+1

多態性を使用しなければならないときは、汚いトリックとみなされます。 –

0
+0

仮想として宣言しますか?メソッドは基本クラスには存在しません。 –

+0

基本クラスのメソッドは、サブクラス実装の "override"キーワードとともに、仮想である必要があります。下の私の答えを見てください。 –

+0

@Kevin:メソッドは基本クラスにはありません。私はあなたの答えにさらにコメントしました。 –

3

私は何かが欠けているが、なぜ作り、それらのメソッドを持つインターフェイスから継承していない可能性があります?

インスタンスの作成プロセスを制御している場合は、作成していないクラスから継承し、インターフェイスを追加することで、必要なものを得ることができます(コードを書く必要はありません。既存の非仮想メソッドへのインタフェース)。

+0

彼はクラスを制御できません。 –

+0

もっと具体的にする必要があるかもしれません...;) – Lucero

+0

右。これは私が始めたものですが、クラスをコントロールすることはできません。私はそれをすることはできません。 –

0

Visual Studio 2008を使用している場合は、基本クラスの拡張メソッドを作成できます。その拡張メソッドの中で、キャストを行い、サブクラスのメソッドを呼び出します。これは、限り、あなたは他の提案の反射コードを借りVS 2008 withingからコンパイルしているとして、あなたは次のことを行うことができます...

public static class MyExtensions 
{ 
    public static ItemBaseClass CreateNewItem(this BaseClass item) 
    { 
     return item.GetType().InvokeMember("MethodName", System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */); 
    } 
} 
+0

いくつかのコードサンプルを表示できますか?私はそれをきれいにすることは可能だとは思わない。 –

+0

これは良い考えですが、このような大きなスイッチブロックを排除することがポイントです。しかし、ありがとう。 –

+0

スイッチブロックが不要な場合は、反射ルートを使用してください。性能が懸念される場合、スイッチブロックがより良いルートかもしれません。拡張メソッドを使用すると、スイッチボックを簡単に呼び出し可能なメソッドに分離できます。第2の考えとして –

0

別の可能性が使用するだけでなく2.0フレームワークの対象プロジェクトのために働く必要がありますRealProxy(パフォーマンス面ではあまり効率的ではない)などのプロキシメカニズムや、ダイナミックに作成されたDynamicMethodを使用することで、リフレクションを使用するオーバーヘッドがサポートするタイプごとに1回しかなく、リフレクションメソッド。このメソッドを何回か呼び出す必要がある場合、これは大きな効果がありますが、MSILの知識が必要です。

-1

サブクラスのメソッド定義に "override"キーワードがありません。何かが「抽象的な」と宣言されたとき、それは仮想的に定義されているので、サブクラスでは、メソッド宣言の前に "override"キーワードを置く必要があります。したがって、動作する必要があるのは以下のとおりです。

BaseClass{ 
    abstract void Add(ItemBaseClass item); // not present! 
    abstract ItemBaseClass CreateNewItem(); // not present! 
} 

SubClassA : BaseClass{ 
    override void Add(ItemA item) {...} 
    override ItemA CreateNewItem() {...} 
} 

SubClassB: BaseClass{ 
    override void Add(ItemB item) {...} 
    override ItemB CreateNewItem() {...} 
} 

これは、使用例の場合とまったく同じです。

+0

@ケビン、助けてくれてありがとう、私が示したかったことは、私がそのコードに触れることができないということです。私はそれを制御しません。 //現在の行は実際にはコードファイルにありません。もしそれらがあれば、私は金色になります。 –

+0

ああ、そうです。つまり、基本的には、共通のインタフェースを宣言していないものに対して、インタフェースのような動作を探しています。一般的な方法のものは、インターフェイスを実装していない場合、ちょっとしたデザインです。残念な。 –

0

問題#1:あなたのサブクラスは何 問題#2をオーバーライドしていない:あなたのサブクラスは、あなたの基底クラスとは異なる関数シグネチャを持つ

あなたがそれらをオーバーライドしている場合、あなたの署名が正しいこと、およびことを確認し、マークそれらは仮想で抽象ではない。基本クラスの仮想関数に何もしたくない場合は、空の本体を追加する必要があります。

class ItemBase{} 

class ItemA : ItemBase{} 

class ItemB : ItemBase{} 

class BaseClass 
{ 
    public virtual void Add(ItemBase item){} 
    public virtual ItemBase CreateItem() { return null; } 
} 

class ClassA : BaseClass 
{ 
    public override void Add(ItemBase item) 
    { 
     //do whatever 
     throw new NotImplementedException(); 
    } 

    public ItemBase CreateItem() 
    { 
     //create an ItemBase and return 
     throw new NotImplementedException(); 
    } 
} 
+0

MStodd、提案をいただきありがとうございますが、残念ながら私はクラスを制御できません。さらに、これらのメソッド呼び出しは、抽象クラスまたはコンクリートの基本クラスに実際には存在しません。 –