2009-04-16 110 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對象的公共基類,併爲項目對象的公共基礎課,我曾希望從多態性的精彩世界受益。

不幸的是,由於常用的方法實際上並不存在於基類中,所以我無法虛擬地調用它們。例如,這將是完美的:

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 

Againt,我有過這些類(我認爲排除了部分類)沒有控制。

+0

那麼你自己的方法有什麼問題呢?只有使用我的,如果你有選項嚴格在 – 2009-04-16 18:20:39

+0

10你有控制的子類?如果你這樣做,去Lucero的解決方案。 – 2009-04-16 18:25:03

+1

@邁克爾哈倫:C#根本沒有Option Strict。如果你對這些類沒有控制權,我的解決方案就可以工作,如果你能控制子類,Lucero的解決方案是最好的。 – 2009-04-16 18:25:58

回答

6

您不能通過反射或其他骯髒的技巧調用派生類的非虛方法。如果你想這樣做,它是那麼容易:

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

我願意使用骯髒的技巧!如果VB高興地接受它,它不會* *那麼瘋狂......好吧,它可以,但我想看... – 2009-04-16 18:16:17

+0

爲什麼反射髒的詭計? :) 它現在很常見,你甚至可以使它無代碼地執行代碼 – majkinetor 2009-04-16 18:16:42

+1

當你需要使用多態時,它被認爲是一個骯髒的技巧。 – 2009-04-16 18:17:24

3

我可能失去了一些東西,但爲什麼不從這些方法的接口繼承?

如果你在控制實例的創建過程,你可能通過從你沒有編寫的類繼承而得到你想要的,然後添加接口(不需要編寫代碼,編譯器將映射現有非虛擬方法的接口)。

0

如果您使用的是Visual Studio 2008,則可以爲基類創建擴展方法。在該擴展方法內部,您可以執行強制轉換並調用子類的方法。這應該爲2.0框架針對性的項目從withing VS 2008年借用其它推薦的反射代碼工作爲好,只要你編譯,你可以做以下...

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

另一種可能性是使用一些代理機制,比如RealProxy(儘管性能不是很高效),或者使用動態創建的DynamicMethods更好,這樣使用反射的開銷只有每種類型支持一次,同時保持它與反射方法一樣靈活。當你需要多次調用該方法時,這會帶來很大的收益,但它需要一些MSIL知識。

-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() {...} 
} 

這應該正是按照您在您的使用示例希望。

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(); 
    } 
}