2

私は、一連のクラスを生成するライブラリを使用しています。

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

例えば:

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

明らかにキャストは機能しますが、その場合、メリットを無効にするタイプを知る必要があります。

これらのメソッドの呼び出しを「強制」するにはどうすればよいですか? 呼び出そうとしているメソッドを実装していないオブジェクトを取得する心配はありません。私は実際にVBでやりたいことをすることができます - 私はインテリセンスを得ることはできませんが、コンパイラは満足して動作します:

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

繰り返しますが、私はこれらのクラスを制御することはできません (部分クラスを除外すると思います)。

4

7 に答える 7

6

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

// obj is your object reference.
obj.GetType().InvokeMember("MethodName", 
    System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */)
于 2009-04-16T18:13:50.417 に答える
3

何かが欠けているかもしれませんが、これらのメソッドを使用してインターフェイスを作成して継承してみませんか?

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

于 2009-04-16T18:22:42.253 に答える
0

もう 1 つの可能性は、RealProxy (パフォーマンスの点ではあまり効率的ではありません) などのプロキシ メカニズムを使用するか、動的に作成された DynamicMethods を使用して、リフレクションを使用するオーバーヘッドがサポートする型ごとに 1 回だけになるようにすることです。リフレクション方式として柔軟。これは、メソッドを複数回呼び出す必要がある場合に大きな効果を発揮しますが、MSIL の知識が必要です。

于 2009-04-16T18:30:34.543 に答える
0

それらを仮想として宣言します。

http://msdn.microsoft.com/en-us/library/9fkccyh4(VS.71).aspx

于 2009-04-16T18:14:42.880 に答える
0

Visual Studio 2008 を使用している場合は、基本クラスの拡張メソッドを作成できます。その拡張メソッド内で、キャストを行い、サブクラスのメソッドを呼び出します。これは、VS 2008 を使用してコンパイルしている限り、2.0 フレームワークを対象としたプロジェクトでも機能するはずです。他の提案されたリフレクション コードを借りると、次のことができます...

public static class MyExtensions
{
   public static ItemBaseClass CreateNewItem(this BaseClass item)
   {
      return item.GetType().InvokeMember("MethodName", System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */);
   }
}
于 2009-04-16T18:26:57.780 に答える
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();
    }
}
于 2009-04-16T18:40:42.163 に答える
-1

サブクラスのメソッド定義で「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() {...}
}

これは、使用例で必要に応じて正確に機能するはずです。

于 2009-04-16T18:35:39.850 に答える