2017-09-25 92 views
-2

我不確定用什麼技術術語來描述這種情況,所以這裏是我的情況。C#:函數返回類型覆蓋對象轉換嗎?

語境:

我設計一個項目系統遊戲。目前,存在一個包含基本參數(如Id,名稱,圖標等)的BaseGameItem類... 迄今爲止,還存在從它派生的另一個類,稱爲PickupItem,它實現了IPickupItem。所有似乎都很好,直到我嘗試通過Item Spawner初始化這些對象。

的關鍵思想是,存在一個持久的數據庫,所述 產卵指初始化對象時,它然後前進到 吐出如所示的完全初始化的對象:

 /// <summary> 
    /// Initialize Game Item: 
    /// Given an Item ID, constructs a BaseGameItem object and returns it to instigator. 
    /// Refers to ItemInfoTable to initialize object parameters. 
    /// </summary> 
    /// Paramater - Int ID: The provided Item ID 
    /// Parameter - out BaseGameItem Item: The constructed object returned to the instigator. 
    public static void InitializeGameItem(int id, out BaseGameItem item) 
    { 
     FItemInfoData itemInfoData = ItemTable.Find(x => x.ItemID == id); 

     if(itemInfoData.ItemID != id) 
     { 
      itemInfoData = ItemTable[0]; 
     } 

     // Check if item is a Pickup. If so, then item is returned as a PickupPlaceable. 
     // Otherwise, initialize to BaseGameItem. 
     item = itemInfoData.IsPickupItem ? new PickupPlaceable() : new BaseGameItem(); 

     item.SetItemName(itemInfoData.ItemName); 
     item.SetItemDescription(itemInfoData.ItemDescription); 
     item.SetItemIcon(itemInfoData.ItemIcon); 
     item.SetItemMesh(itemInfoData.ItemMesh); 
    } 

我的問題如下:

  1. 爲了知道我應該返回哪個類或項目是實現什麼接口ing,我在數據庫中包含一個布爾值,檢查它是否是Pickup對象。這是一個明智的決定嗎?如果您能指導我閱讀這種場景中使用的文章或設計模式,我將非常感激。
  2. 但我主要關心的是返回類型。我使用out關鍵字並輸出一個BaseGameItem對象。但是,在我的三元條件下,我可以將其初始化爲派生Pickup項目。函數輸出是否會將其強制轉換爲BaseGameItem,並因此會丟失所有拾取功能?或者它是否將任何派生類解釋爲有效的返回類型?
  3. 如果將對象作爲BaseGameItem返回,不管接收者是否應該知道他們必須將其轉換爲派生類?如何解決這個問題,我是否簡單地返回一個布爾值,指示它是初始化函數內的Pickup,以便接收者知道何時適當地進行轉換?
+0

當你真正運行的代碼發生了什麼事? – Servy

+0

我認爲這個問題更適合於[代碼評論](https://codereview.stackexchange.com/) – Xiaoy312

+0

值得注意的是,當你投射時你不會失去對象上的功能;你只是失去了訪問功能。 –

回答

0
  1. 爲了知道我應該返回或項目實現什麼接口,類,我來檢查,如果它是一個皮卡對象的數據庫包含一個布爾值。這是一個明智的決定嗎?如果您能指導我閱讀這種場景中使用的文章或設計模式,我將非常感激。

你在正確的軌道上factory method

  • 我最關心的是但返回類型。我使用out關鍵字並輸出一個BaseGameItem對象。但是,在我的三元條件下,我可以將其初始化爲派生Pickup項目。函數輸出是否會將其強制轉換爲BaseGameItem,並因此會丟失所有拾取功能?或者它是否將任何派生類解釋爲有效的返回類型?

  • 返回類型將不會從上溯造型失去功能:

    基類可以定義和實現虛方法和派生類可以覆蓋他們,這意味着他們提供自己的定義和實現。在運行時,當客戶端代碼調用該方法時,CLR將查找該對象的運行時類型,並調用該虛擬方法的重寫。因此,在您的源代碼中,您可以調用基類上的方法,並使該方法的派生類的版本得以執行。

    - Polymorphism (C# Programming Guide)

  • 如果對象而不管返回BaseGameItem,不應該接收器知道,他們必須將它轉換爲衍生類?如何解決這個問題,我是否簡單地返回一個布爾值,指示它是初始化函數內的Pickup,以便接收者知道何時適當地進行轉換?

  • 不行,「因此,在你的源代碼,你可以調用基類的方法,並導致執行派生類的版本的方法。」但是,當你需要從派生類的特定功能,如PickupPlaceable.Pickup(),你將不得不垂頭喪氣首先

    編輯:

    的問題來了,如何不接收器知道如果基地項目應投。

    您可以隨時檢查,如果一個項目可以使用isas關鍵字被拾起:

    if (item is PickupPlaceable) 
    { 
        var loot = (PickupPlaceable)item; 
        loot.Pickup(); 
    } 
    
    var loot = item as PickupPlaceable; 
    if (loot != null) 
    { 
        loot.Pickup(); 
    } 
    
    +0

    感謝您的精心迴應!關於最後兩點,我覺得我的設計沒有采用這種方法,對嗎?因爲BaseGameItem類根本不實現Pickup接口來開始。即使它們不被父級使用,是否可以用虛擬方法「污染」父類?請注意,爲了練習,我打算派生另一個名爲「Interactable」的類,它也不應該具有Pickup功能。 –

    +1

    @AAS.N當然可以使用抽象方法,但在你的情況下,我認爲你應該使用接口,例如你可以使用Pick方法使用Pickeable接口,然後你想要選擇的每個項目都可以實現界面,同樣適用於Interactable。 – FilipRistic

    +0

    @FilipRistic是的,這正是我最初設計它的方式。這個問題源於Pickup類是BaseGameItem類的一個子類。只有Pickup類實現了IPickup,因爲基類可以是不適合拾取的對象的父類。因此,只要item spawner嘗試初始化遊戲項目,就必須輸出一個BaseGameItem對象,如上面的代碼所示。然後接收對象的類必須將其轉換爲實現所需功能的特定子對象。問題變成了,接收者如何知道是否應該投射基礎物品。 –