2013-04-05 45 views
2

我不知道我怎麼能解釋這個,所以我只是展示我的例子和詳細說明。c#沒有根據參數類型(繼承)選擇我想要的函數

using System; 

namespace Demo 
{ 
    static class Program 
    { 
     static void Main() 
     { 
      var test = new ExampleClass(new Bar()); 

      Console.WriteLine(test); 
     } 
    } 

    class ExampleClass { 
     public Foo _foo; 

     public ExampleClass(Bar bar) 
     { 
      _foo = bar; 
     } 

     public override String ToString() { 
      return print(_foo); 
     } 

     String print(Bar bar) { 
      return bar.Name; 
     } 

     String print(Foo foo) { 
      return foo.ToString(); 
     } 
    } 

    class Bar : Foo 
    { 
     public String Name; 
    } 

    class Foo 
    { } 
} 

好吧,這是行不通的。

雖然我可以看到_foo的類型是Foo在聲明中,它也可以是Bar,因爲它繼承了Foo

我的問題是:

爲什麼不編譯器看到的實際類型的_foo

爲什麼print(Foo)總是執行,儘管該類型是Foo的派生類?

編輯

編輯我的示例代碼,因爲它仍然含有得多的我原來的代碼。

感謝Anthony Pegram的例子。

+0

爲什麼不知道?簡單地說,因爲這在運行時很難理解,並且會顯着降低性能。 – antonijn 2013-04-05 15:46:19

+5

請顯示SyntaxNode的定義。 – driis 2013-04-05 15:46:30

+0

由於@driis指出,你沒有定義'SyntaxNode',它可能是任何東西,並給一個變量與關鍵字相同的名稱,如'base',這是一個壞主意。 – Jodrell 2013-04-05 16:08:32

回答

2

您的代碼不會格外證明你的問題很好,因爲你已經出臺SyntaxNode類型的字段沒有顯示它如何與您的BaseClass/BaseClassExtension類型層次。但是,當給予可理解的類型時,仍然有某些東西可以回答。

我的問題是:爲什麼不.net運行時查看originalNode的實際類型?爲什麼總是打印(BaseClass),儘管類型是BaseClassExtention?

.NET運行時不是什麼決定使用哪個超載。這是編譯器的一個屬性,它使用關於變量(或字段,屬性)類型的信息來確定使用哪個超載。

一個簡單的演示。假設我們有

class Foo { } 
class Bar : Foo { } 

void Do(Foo foo) 
{ 
    Console.WriteLine("Foo overload"); 
} 

void Do(Bar bar) 
{ 
    Console.WriteLine("Bar overload"); 
} 

然後,你還要代碼

Foo foo = new Bar(); 
Do(foo); 

你碰巧是指Bar類型的對象Foo類型的變量。編譯器會發出代碼來在編譯時調用Foo過載,因爲這就是它所知道的,並且坦率地說,這就是您要求它做的事情。 (事實上​​,我們將它初始化爲上一行中的Bar類型的對象並不特別相關。在下一行,只是認爲foo可能來自隨時隨地,我們知道那是什麼變量fooFoo類型。)

如果你想在運行時使用更具體的過載,你可能會探索雙派遣機制,如Visitor Pattern。我不特別推薦的另一種方法是通過關鍵字dynamic在運行時確定類型(如果問題很好理解,通常會有更好的選擇,但有時適合)。

Foo foo = new Bar(); 
Do((dynamic)foo); 

運行時動態的語義是你可以在自己的時間研究的東西,但是這樣可以有效地產生你所期望的結果。

+0

謝謝!動態演員似乎已經成功了! – 2013-04-09 09:31:06

0

我試過了,但是如果類SyntaxNode派生自BaseClassExtention類,它會按預期工作 - 所以很難從你向我們展示的代碼中分辨出問題所在。

這個工程,我會期望:

using System; 

namespace Demo 
{ 
    static class Program 
    { 
     static void Main() 
     { 
      var test = new myNode(); 

      Console.WriteLine(test); 
     } 
    } 

    class myNode 
    { 
     public SyntaxNode originalNode = new SyntaxNode{Name = "SyntaxNode"}; 

     public override string ToString() 
     { 
      return print(originalNode); // This calls print(BaseClassExtention Class) 
     } 

     string print(BaseClassExtention Class) // <= This gets called. 
     { 
      return Class.Name; 
     } 

     string print(BaseClass b) 
     { 
      return b.ToString(); 
     } 
    } 

    class BaseClass 
    {} 

    class BaseClassExtention : BaseClass 
    { 
     public string Name { get; set; } 
    } 

    class SyntaxNode: BaseClassExtention 
    { 

    } 
} 
0

看起來您預計將根據originalNode的運行時類型選擇print。 C#在編譯時選擇要調用的函數 - print不是虛方法,因此必須在編譯時解析調用。

所以,你必須

public SyntaxNode originalNode; 
string print(BaseClassExtention Class)... 
string print(BaseClass base)... 

在編譯時的2個打印功能將被選擇(基於如果SyntaxNodeBaseClassBaseClassExtension)。如果SyntaxNode派生自BaseClassExtension而不是string print(BaseClassExtention Class)版本(因爲它比BaseClass更具體),否則可以使用兩者),否則使用其他版本。

如果您想根據的originalNode您需要可以調用originalNode某些虛擬方法的print部分或手動檢查類型,做你的print方法的內在的東西運行時類型的行爲是不同的。