2008-09-17 100 views
5

我想問的問題在C#「寬鬆」打字是這樣的:鑄造沿着繼承樹

從一個抽象類情有可原內鑄造沿着繼承樹(即朝着更specialiased類)。甚至是一件好事,還是總是一個可憐的選擇,有更好的選擇?

現在,爲什麼我認爲它可以用於良好的例子。

我最近在C#中實現了Bencoding from the BitTorrent protocol。一個足夠簡單的問題,如何表示數據。我選擇這樣做,

我們有一個abstract BItem類,它提供了一些基本功能,包括用於將Bencoded字符串解碼爲必要結構的static BItem Decode(string)

還有四個派生類,BStringBIntegerBListBDictionary,表示待編碼的四個不同的數據類型。現在,這是棘手的部分。 BListBDictionary分別具有this[int]this[string]訪問器以允許訪問這些數據類型的類似數組的質量。

潛在的可怕的部分現在快到:

BDictionary torrent = (BDictionary) BItem.DecodeFile("my.torrent"); 
int filelength = (BInteger)((BDictionary)((BList)((BDictionary) 
      torrent["info"])["files"])[0])["length"]; 

那麼,你得到的圖片...哎喲,這是很難的眼睛,更不用說大腦。所以,我介紹了一些額外的成抽象類:

public BItem this[int index] 
{ 
    get { return ((BList)this)[index]; } 
} 
public BItem this[string index] 
{ 
    get { return ((BDictionary)this)[index]; } 
} 

現在,我們可以把舊的代碼爲:

BDictionary torrent = (BDictionary)BItem.DecodeFile("my.torrent"); 
int filelength = (BInteger)torrent["info"]["files"][0]["length"]; 

哇,變戲法似的,更可讀的代碼。但是,我是否僅僅爲了暗示子類的知識而將部分靈魂出售給抽象類?

編輯:在回答一些進來的答案,你完全偏離軌道了這個特殊的問題,因爲結構是可變的,例如我的torrent["info"]["files"][0]["length"]例子是有效的,但這樣是torrent["announce-list"][0][0],都將是在90%的torrent文件中。泛型是不是要走的路,與這個問題atleast :(。點擊通過規範我鏈接,它只有4個小點的大點。

+0

我震驚了! :) – 2008-09-17 10:58:30

回答

5

我想我會使這[int]和這[string]訪問器虛擬並在BList/BDictionary中覆蓋它們。訪問器沒有意義的類應該施加NotSupportedException()(可能通過在BItem中具有默認實現)。

這使得以同樣的方式你的代碼的工作,讓您在情況更可讀的錯誤,你應該錯誤地寫

(BInteger)torrent["info"][0]["files"]["length"]; 

+0

作爲一個旁註,這是我實際上正在做的,除了我使用new來覆蓋而不是虛擬/覆蓋。愚蠢,愚蠢。更清潔,更好的解決方案,謝謝! – 2008-09-17 11:42:26

+1

'new'實際上並未覆蓋。你只要得到兩個同名的方法 - 如果有人投向基類,然後調用方法,他們將獲得原始的基類方法,而不是覆蓋的方法 – 2008-09-18 00:10:16

3

你真的不應該從基地訪問任何派生類因爲它很大程度上打破了OOP的概念,可讀性肯定會有很大的提高,但是我不會爲了可重用性而進行交易,考慮一下你需要添加另一個子類的情況 - 你還需要更新基類因此類

1

如果文件長度是你經常檢索的東西,爲什麼不落實的BDictionary屬性類......,讓你的代碼變得(?):

BDictionary torrent = BItem.DecodeFile("my.torrent"); 
int filelength = torrent.FileLength; 

這樣,用戶就可以隱藏實現細節。

+0

如果你閱讀規範(鏈接到,並且長6行),BDictionary可以在數據結構中的任何地方,所以這個答案根本沒有意義,對不起。 – 2008-09-17 11:13:32

0

你有沒有海外商品會有解析一個簡單的「路徑」,所以你可以這樣寫:

BDictionary torrent = BItem.DecodeFile("my.torrent");
int filelength = (int)torrent.Fetch("info.files.0.length");

也許不是最好的方式,但可讀性上升(少許)

0
  • 如果您完全控制了您的代碼庫和思考過程,那麼務必採取一切行動。
  • 如果沒有,您會後悔當天某些新人注入了您沒有看到您的 BList或BDictionary的BItem派生。

如果必須這樣做,atleast會在強類型方法簽名的類中包裝它(控制對列表的訪問)。

BString GetString(BInteger); 
SetString(BInteger, BString); 

即使您在內部將其存儲在BItems的BList中,也會接受並返回BString。 (讓我分開之前,我做我的2 B或不2 B)

0

嗯。我實際上會爭辯說,編碼的第一行比第二行更具可讀性 - 要弄清楚發生了什麼,花費更長的時間,但它更像是將對象視爲BList或BDictionary。將這些方法應用到抽象類中隱藏了這些細節,這可能會讓您很難弄清楚您的方法實際上在做什麼。

1

我看到它的方式,並非所有的BItems都是集合,因此並非所有的BItems都有索引器,所以索引器不應該放在BItem中。我會從BItem派生另一個抽象類,我們將其命名爲BCollection,並把索引存在,是這樣的:

abstract class BCollection : BItem { 

     public BItem this[int index] {get;} 
     public BItem this[string index] {get;} 
} 

,使BList和BDictionary從BCollection繼承。 或者你可以多走一步,讓BCollection成爲一個通用類。

+0

訪問者的返回BItem的,但這仍然沒有幫助任何長期的申請。 – 2008-09-17 11:12:10

0

如果您引入泛型,您可以避免投射。

class DecodedTorrent : BDictionary<BDictionary<BList<BDictionary<BInteger>>>> 
{ 
} 

DecodedTorrent torrent = BItem.DecodeFile("mytorrent"); 
int x = torrent["info"]["files"][0]["length"]; 

嗯,不過那可能是行不通的,因爲這些類型也取決於你採取通過結構的道路上。

+0

EEK!好吧,這個(非常)具體的例子...但實際上,它是一個可變的樹結構... `torrent [「info」] [「files」]`是有效的。但是`torrent [「announce-list」] [0] [0]`也是如此。你的泛型剛剛破解:( – 2008-09-17 11:34:45

0

難道只是我

BDictionary torrent = BItem.DecodeFile("my.torrent");int filelength = (BInteger)((BDictionary)((BList)((BDictionary)    torrent["info"])["files"])[0])["length"]; 

你不需要BDictionary投「種子」被聲明爲BDictionary

public BItem this[int index]{&nbsp; &nbsp; get { return ((BList)this)[index]; }}public BItem this[string index]{&nbsp; &nbsp; get { return ((BDictionary)this)[index]; }} 

這些不acheive期望的結果返回類型仍然是抽象版本,所以你仍然需要施放。

重寫的代碼必須是

BDictionary torrent = BItem.DecodeFile("my.torrent");int filelength = (BInteger)((BList)((BDictionary)torrent["info"]["files"])[0])["length"]; 

哪個是一樣糟糕的第一批

+0

中間部分被添加到抽象類(BItem)中,因此他們有訪問器,不需要再施放它們來使用它們。 – 2008-09-17 12:22:34

1

我的建議是推出更多的抽象。我發現令人困惑的是一個BItem有一個DecodeFile(),它返回一個BDictionary。這可能是一個合理的事情,在洪流領域做,我不知道。

不過,我會找到像以下較爲合理的API:

BFile torrent = BFile.DecodeFile("my.torrent"); 
int filelength = torrent.Length;