2013-01-25 47 views
4

在一個應用程序中,我需要.NET根據它的運行時類型而不是它的編譯時類型來調用一個方法。基於編譯時類型的運行時類型insead的調用方法

簡單的例子:

class A { } 

    class B : A { } 

    static void Main(string[] args) 
    { 
     A b = new B(); 
     Print(b); 
    } 

    static void Print(A a) 
    { 
     Console.WriteLine("Called from A"); 
    } 

    static void Print(B b) 
    { 
     Console.WriteLine("Called from B"); 
    } 

上面的代碼將實際打印Called from A,但我需要它Called from B

這按預期工作:

static void Print(A a) 
{ 
    var b = a as B; 
    if (b != null) 
     return Print(b); 
    else 
     Console.WriteLine("Called from A"); 
} 

但對於可維護性的緣故,這是不可取的。

我相信這個問題類似於這個:Why isn't this method chosen based on the runtime-type of its object?,但是.NET代替了Java。

+1

除非有一個很好的理由打印是一個靜態成員.. ..打印應該是A&B的實例成員。然後,您可以使方法變爲虛擬並在B中重寫以完成此任務。 –

+0

@ P.Brian.Mackey我可能會這樣做,如果可以的話,但我不能改變它們。 – Meryovi

回答

9

最簡單的方法,如果你使用.NET 4或更高版本是使用dynamic typing

​​

幾乎使用dynamic類型的值所有表達式將被動態調用,用一個「小C#編譯器「在執行時應用與編譯時相同的規則,但使用這些動態值的執行時間類型。 (雖然在編譯時靜態已知的表達式仍將被視爲具有這些類型,但它並不會將所有關於超載分辨率的所有內容都變爲動態的。)

如果您不使用.NET 4,這有點難度 - 你可以使用反射,或者對選項進行硬編碼,這兩者都不是很有趣。

+0

喬恩,只會影響調度而不是改變'b'變量嗎?例如'Print((dynamic)b);'? –

+0

@羅伊:爲什麼?如果你沒有使用這個變量來做其他事情,你期望它有什麼不同? –

+0

由於他寫了_Simplified示例:_我認爲它可以是'b'稍後被引用的情況。所以我不希望他失去對智能未來用途的智能感知。無論如何不要介意。對於_his確切sample_它是相同的。 –

5

您可以使用dynamic類型:

A b = new B(); 
dynamic tmp = b; 
Print(tmp); // Prints "Called from B" 

但是,請注意,這有退縮,這將產生一個運行時異常,而不是一個編譯錯誤,如果沒有匹配的方法。

4

使用覆蓋OOP。

〔實施例:

class A { 

    public virtual void Print() { 
      Console.WriteLine("Called from A"); 
    }  
} 

class B : A { 
    public override void Print() { 
      Console.WriteLine("Called from B"); 
    } 
} 

,並用它喜歡:

A b = new B(); 
    Print(b); 


    static void Print(A a) 
    { 
     a.Print(); //will run B's method 
    } 

它將運行運行類型的方法,你用簡單的壓倒一切的理念。

+0

它的工作,但在我的現實世界的情況下,我需要它的工作基於參數,而不是繼承。 – Meryovi

+0

這,我寧願看到這個比'動態'。 (但是,如果它不可能......':(') – Rawling

+0

@Rawling:但是,只有當這個方法實際上可以在'A'上定義時纔有效,有很多情況是不可能的 –

0

這不是多態如何工作。您應該考慮做類似的東西以下代替:

class A 
{ 
    virtual string GetString() 
    { 
     return "Called from A"; 
    } 
} 

class B : A 
{ 
    override string GetString() 
    { 
     return "Called from B"; 
    } 
} 

static void Main(string[] args) 
{ 
    A b = new B(); 
    Print(b); 
} 

static void Print(A a) 
{ 
    Console.WriteLine(a.GetString()); 
} 
0

試試這個:

class A 
{ 
    public virtual string Print() 
    { 
     return "Called from A"; 
    } 
} 

class B : A 
{ 
    public override string Print() 
    { 
     return "Called from B"; 
    } 
} 

和其他地方進行測試

A b = new B(); 
MessageBox.Show(b.Print()); //called from B 
相關問題