2009-04-21 14 views
1

ジェネリックスと新しいメンバーに問題があります。 ObjectA型のオブジェクトで動作するジェネリッククラスを作成しました。 ObjectBはObjectAから派生し、ObjectAのメンバーのいくつかを隠します。型パラメータとしてObjectBの型を汎用クラスに指定すると、ObjectBによって隠されたメンバのいずれかを呼び出すと、ObjectBの実装を呼び出すことになると思います。ただし、CLRは依然として非表示メンバー(ObjectAの実装)を呼び出します。これは、ObjectBの型をジェネリッククラスに明示的に提供したため、非論理的です。これはジェネリック医薬品自体の問題ですか、何か間違っていますか?ジェネリックス:非公開のメンバーではなく新メンバーへのアクセス

編集:残念ながら、私はObjectAのソースコードにアクセスできず、上書きしたいメンバは仮想ではありません。 ObjectAのソースコードにアクセスできれば、メンバーを仮想化できますが、できないので、メンバーを「上書きする」ための唯一の選択肢は「新しい」キーワードです。

class GenericClass<T> where T : ObjectA 
{ 
    public void DoWork(T item) 
    { 
     // When type parameter 'T' is ObjectB, should get ObjectB's implementation 
     item.Invoke(); 
    } 
} 

class ObjectA 
{ 
    public void Invoke() 
    { 
     // A's implementation... 
    } 
} 

class ObjectB : ObjectA 
{ 
    public new void Invoke() 
    { 
     // B's implementation... 
    } 
} 

static void Main() 
{ 
    GenericClass<ObjectB> genericClass = new GenericClass<ObjectB>(); 
    ObjectB objectB = new ObjectB(); 
    genericClass.DoWork(objectB); 
} 

答えて

7

号コンパイラによって生成されたコールは、それがコンパイル時で知っているメンバーにあります。それはObjectAによって公開されたメンバーです。

仮想継承とオーバーライドされたメソッドで通常の継承を使用していない理由は何ですか?ここで

は仕方によって、ものと同じ種類の別の例だ - の文字列のため、オーバーロード==演算子は使用されず、TFooへの呼び出しでstringあるにもかかわらず:

using System; 

class Test 
{ 
    static bool Foo<T>(T first, T second) 
     where T : class 
    { 
     return first == second; 
    } 

    static void Main() 
    { 
     string x = "hello"; 
     string y = new string(x.ToCharArray()); 

     Console.WriteLine(Foo(x, y)); 
    } 
} 
+0

あなたの答えをありがとう。仮想/オーバーライドされたメソッドを使用しますが、System.Windows.Formを継承していて、仮想ではないメンバーのために独自の実装を作成しようとしています。 –

+0

それで、あなたはこのようにアクセスすることはできません。あなたはそれを "ほぼ仮想"にしようとしているように思えます。それはそのようには機能しません。 –

+0

Hm。あなたがC++テンプレートに慣れていれば、これはやや直感的ではないと私は同意します。 C#はテンプレートクラスのコンパイルを行い、そのときのObjectAについてのみ認識します。テンプレートがインスタンス化されると、インスタンス化されたクラスはObjectBの追加された知識で再コンパイルされません。 –

0

この5月あなたの質問に対する答えではありませんが、私はあなたのアプローチのポイントを見ません(私は単純な例を見るだけなので、そうかもしれません)。

私は、次のアプローチを使用することをお勧めします:

class ObjectA 
{ 
    public virtual void Invoke() 
    { 
     // do some work 
    } 
} 

class ObjectB : ObjectA 
{ 
    public override void Invoke() 
    { 
     // do some other work 
    } 
} 

class GenericNotNeededClass 
{ 
    public void DoWork(ObjectA item) 
    { 
     item.Invoke(); 
    } 
} 


static void Main() 
{ 
    GenericNotNeededClass nonGenericClass = new GenericNotNeededClass(); 
    ObjectB objectB = new ObjectB(); 
    nonGenericClass.DoWork(objectB); 
} 

私は、そのコードは、あなたのコード例に基づいて、探しているものを行いますと信じています。

0

Tは、ジェネリックのObjectAタイプであると定義します。 Invoke()が仮想であれば、あなたは考えているように動作しますが、そうではないため、ジェネリックはObjectAの実装を呼び出します。これは、Tが定義されているためです。

これは、Invoke()のObjectB実装を指す仮想メソッドテーブルエントリがないため、これはランタイムがすべて呼び出すことができるためです。仮想メソッドの場合は、VMTにメソッドアドレスがあり、それがあなたが思うように動作します。

関連する問題