2012-08-28 120 views
2

所以我想創建一個類型的擴展方法,該API另有密封。實例化擴展方法? C#

如果您瞭解擴展方法,以下內容應該看起來很熟悉。

private static List<Member> memberList = new List<Member>(); 

public static List<Member> GetMemberList(this GameObject go) 
{ 
    return memberList; 
} 

注意,聲明一個擴展方法,它需要是靜態的,並且因爲它需要是靜態的,那Im通過遊戲對象類型訪問該列表必須是靜態到。 我希望每個GameObject擁有自己的成員列表。然而,林相當肯定,因爲這是一個靜態字段,每個實例化的GameObject將指向相同的靜態memberList。

那麼我的假設是真的嗎?如果是這樣,有什麼可以替代?我想避免將GameObject放入一個包含memberList的包裝類中,因爲api只允許在運行時檢測和操作GameObjects。有許多方法可以通過gameObject反向引用包裝類,但是這給我想要避免的代碼增加了更多的複雜性。

+1

您將在'GameObject'實例上調用'GetMemberList',它將返回該實例的列表。我不認爲我看到了問題。 (擴展方法是靜態的,並且必須聲明爲靜態類型,但「extended」參數是一個實例。) –

+0

這是我的問題,如果這會發生。另外我只是從另一個網站上讀到這個「擴展方法是一種特殊的靜態方法,但是它們被稱爲是擴展類型的實例方法。」但是靜態memberList呢?它是一個從擴展方法訪問的靜態字段。 – MichaelTaylor3D

+0

@DanJ:問題是成員列表不是遊戲對象的一部分。 – Guffa

回答

2

看起來你正在使用Unity3。 UnityAnswers網站上有相關的答案可能有幫助:http://answers.unity3d.com/questions/22493/unity-3-sealed-class-gameobject-.html

似乎應該有方法可以使用內置腳本系統附加Unity框架中固有的行爲。

+0

因爲是Psychic!+1,我完全忘了組件。我會問這個統一的答案,但我認爲這是一個純粹的C#問題。 – MichaelTaylor3D

+0

一個很好的解決方案最終是使用List的實例版本將組件附加到遊戲對象,然後使用擴展方法作爲讀取友好的方式來訪問它。感謝@Jan指出擴展方法只能擴展行爲而不擴展數據。這幫助我意識到這一點。 – MichaelTaylor3D

+0

因此,谷歌搜索密封類GameObject是一個很好的尋找心理的起點。 –

6

是的,如果你想保留遊戲對象之外的東西並通過擴展方法訪問它,它必須是靜態的。

您可以使用字典來一個成員列表映射到每個遊戲對象:

private static Dictionary<GameObject, List<Member>> memberLists = new Dictionary<GameObject, List<Member>>(); 

public static List<Member> GetMemberList(this GameObject go) { 
    return memberLists[go]; 
} 
+4

+1雖然我想我會提到 - 如果你這樣做,請小心使用,因爲靜態字典會將所有項目保存在列表中,以及GC可訪問的GameObject實例,所以它們永遠不會被GCed。如果你使用這種方法,確保你的'GameObject'實例正確地移除它們,否則你可能會遇到內存問題。 –

+0

這非常有趣,我現在就去試試看。還@Reed Copsey,非常好的一點。如果我想出適當的解決方案,我會把它保存在我的。 – MichaelTaylor3D

+0

除了GC問題,它還會在第一次調用時拋出KeyNotFoundException,它不是線程安全的。 –

0

擴展方法只是簡單地靜態方法,「出現」看起來像實例方法。

但是,它們不會添加靜態方法沒有的任何附加功能,它只是爲了易用性,維護性和可讀性。擴展方法無法訪問受保護/私有成員。

如果GameObject沒有真正密封(即它沒有sealed關鍵字),那麼您可以編寫一個繼承GameObject的類來訪問其受保護的方法/字段/屬性。這隻有在你自己是構建這些對象的人時纔有效。

+0

是的,不幸的是從遊戲對象繼承是禁用的,我無權改變它。 – MichaelTaylor3D

1

是的,你是對的。如果您有一個靜態方法,則該類的所有實例共享相同的數據。致電return memberList;是非法的。它與return this.memberList;相同,並且this在靜態方法中不可用。相反,您必須致電課程:return GameObject.memberList;。但我明白你不是在尋找這個解決方案。

擴展方法旨在創建額外的行爲。如果你想創建額外的數據,使用繼承擴展GameObject類是正確的選擇。

或者,您可以使用表單Dictionary<GameObject, List<Member>>的字典附加memberList。但個人而言,我喜歡如下所示的構圖:

public class myGameObject 
{ 
    public List<Member> memberList { get; set; } 
    public GameObject go { get; set; } 
} 
+0

這個答案的幾個問題,1月1日/返回memberList是一個法律聲明(而不是一個調用),但會返回類靜態成員,而不是實例成員。這絕對不等於返回this.memberList。 2 /擴展一個密封類是不可能的,但是一個使用合成的包裝類會是,但是如果它被一個期望一個GameObject實例的框架所使用,你將不會有好的結果。 –

+0

不幸的是,繼承自gameObject無法完成,因爲它已經被api封了。爲了解決這個問題,我過去創建了類似於你所顯示的包裝類。但它增加了許多額外的複雜度,Id喜歡避免。 – MichaelTaylor3D

1
private static ConditionalWeakTable<GameObject, List<Member>> dict = new ConditionalWeakTable<GameObject, List<Member>>(); 

public static List<Member> GetMemberList(this GameObject go) 
{ 
    return dict.GetOrCreateValue(go); 
} 

ConditionalWeakTable管理對象的生存期,因爲它使用弱引用。因此,如果沒有其他實時引用,它不會阻止GC收集GameObject,並且這也將允許收集List<Member>

它是線程安全的,但是這裏假定你希望你的起點是一個空列表(如果沒有當前值,則在GetOrCreateValue中調用默認構造函數)。如果你想要一個不同的起點,你的線程問題會變得更加複雜。

+0

這是一個很好的選擇,我有很多選項可供選擇。 – MichaelTaylor3D

+0

Tetsujin no Oni似乎是最有趣的賭注,儘管我對自己的團結一無所知。 –