2012-09-26 133 views
2

由於這是我的第一個StackOverflow文章,我想簡要地說一個巨大的感謝管理該站點的那些人以及積極爲他人提供幫助的人。 StackOverflow一直是解決C#代碼挑戰的非常有用的資源。NullReferenceException引用基類派生成員對象的普通成員

類描述:在MS的VisualStudio 2010 C#.NET控制檯應用程序我有以下基/派生層次結構:

  • Entry - >DirEntry
  • Entry - >FileEntry - >AudioFileEntry - >OutputFileEntry

...後三者分別是成員在foll由於鹼/派生層次結構:

  • Directory - >AudioDirectory - >OutputDirectory

...,使得:

  • Directory具有構件public FileEntry[] file_entries;
  • AudioDirectory具有構件public AudioFileEntry[] file_entries;
  • OutputDirectory有成員public OutputFileEntry[] file_entries;

Base類Entry按以下方式聲明:

public class Entry : IComparable 
{ 
    public string name; 
    public int entryID; 
    public int parentID; 
    //(other code omitted) 
} 

Directory也有成員公共DirEntry[] dir_entries;這不存在問題,但請注意DirEntry未覆蓋的任何深度超過Directory (例如,沒有AudioDirEntry)。

問題:NullReferenceException試圖從基類內Directory方法或從其它類內讀file_entries[n]共同成員當類型爲AudioDirectoryOutputDirectory

沒有相關的類,成員或方法是靜態的。我試過使用newoverride無濟於事。試圖使file_entries屬性:

public class Directory 
{ 
    public virtual FileEntry[] file_entries { get; set; } 
} 

public class AudioDirectory : Directory 
{ 
    public override AudioFileEntry[] file_entries { get; set; } 
    //(other code omitted) 
} 

...失敗,錯誤, 「... 'app1.AudioDirectory.file_entries': type must be 'app1.FileEntry[]' to match overridden member 'app1.Directory.file_entries'

目標:的引用file_entries在基類Directory方法的能力,不管該對象的派生類型。我的直覺告訴我,我可能忽略了一些簡單的東西,因爲上面基本上是多態性的全部內容,並且應該是一種在不訴諸新的dynamic類型的情況下實現這一點的方式。

對此提出建議?

-Turbine

回答

3

您的問題是,當您重寫屬性或方法時,您無法更改簽名,即涉及的類型。你可以使用新的修飾符來忽略這個限制,但是你必須非常清楚這意味着什麼(後面會詳細介紹)。在你的情況下,你必須避免在子類中隱式定義屬性,因爲這會在子類中聲明一個與基類中的變量不同的新變量。我的意思是,你的代碼是一樣的:

public class Directory 
{ 
    private FileEntry[] _file_entries; 
    public virtual FileEntry[] file_entries 
    { 
     get { return _file_entries; } 
     set{_file_entries = value;} 
    } 
} 

public class AudioDirectory 
{ 
    private AudioFileEntry[] _sub_file_entries; 
    public new AudioFileEntry[] file_entries 
    { 
     get { return _sub_file_entries; } 
     set{_sub_file_entries = value;} 
    } 
} 

這意味着,當你在AudioDirectory設置file_entries在基類訪問的變量仍然是零。

一個可能的解決方案是這樣的一個:

public class Directory 
{ 
    private FileEntry[] _file_entries; 
    public virtual FileEntry[] file_entries 
    { 
     get { return _file_entries; } 
     set{_file_entries = value;} 
    } 
} 

public class AudioDirectory : Directory 
{ 
    public new AudioFileEntry[] file_entries 
    { 
     get { return (AudioFileEntry[])base.file_entries; } 
     set { base.file_entries = value; } 
    } 
} 

這應該工作,但要注意一個事實,即使用new修飾符迫使編譯時綁定,這意味着,在執行財產取決於聲明變量的類型,而不是實例的實際字體。例如在下面的代碼你有AudioDirectory的一個實例,但file_entries的第一次調用執行AudioDirectory版本,第二個目錄之一:

 AudioDirectory ad = new AudioDirectory(); 
     Directory d = ad; 

     FileEntry[] fa = ad.file_entries; 
     FileEntry[] fb = d.file_entries; 
+0

多謝你們。這聽起來像是動態類型的一個很好的例子,雖然在閱讀這兩個回覆之後,我意識到一個更簡單並且可能運行時更快的解決方案是創建一個包裝類。這是非常令人驚訝的,這是必要的,而我之前的多態不是內置的,但這顯然是C#現有設計的一個缺點,或者至少是一個缺點。 我將AudioFileEntry更改爲AudioFileDetails和OutputFileEntry OutputFileDetails,並且FileEntry將同時具有Entry作爲成員。由於不受支持,因此不會有實際的繼承。 – turbine

+0

......爲了公平起見,我想補充一點,我似乎是通過新的動態類型支持IS之後的多態,我在其他地方已經實現了一個運行時性能沒有那麼重要的領域。 – turbine

0

「 'app1.AudioDirectory.file_entries':類型必須是 'app1.FileEntry []' 到 匹配覆蓋構件 'app1.Directory.file_entries'」

意味着您需要返回您從基類中覆蓋的相同類型:

public class Directory 
{ 
    public virtual FileEntry[] file_entries { get; set; } 
} 

public class AudioDirectory : Directory 
{ 
    public override FileEntry[] file_entries { 
     get 
     { 
      return new AudioFileEntry[] { new AudioFileEntry() }; 
     } 
     set 
     { 
      //(other code omitted) 
     } 
    } 
} 

如果您有其他問題,請提供所有您的碼。

+0

(想說聲謝謝,請看我上面的註釋說明) – turbine

相關問題