[英]Rendering using Weak References, and the GC
我最近開始學習C#
。 我是通過制作游戲來做到這一點的(因為我在C++
對此非常熟悉)。
要繪制到后台緩沖區的對象在構造時通過使用對象的弱引用發送的事件進行“注冊”。 由於C++
智能指針被引用計數,並且(因此)一旦最后一個引用超出范圍就被銷毀,這對我的目的很有效。 但是,在C#
,情況肯定不是這樣。
請考慮以下代碼段:
foreach(WeakReference<DrawableObject> drawable in drawables.ToList())
{
DrawableObject target;
drawable.TryGetTarget(out target);
if(target != null)
{
spriteBatch.Draw(target.Texture, target.Position, target.Rectangle, target.Colour);
}
else
{
drawables.Remove(drawable);
}
}
在C#
,主要問題(因為我確定很可能是其他我尚未理解的)是,在對象的最后一次強引用超出范圍之后, target
不能保證為null
。
強制垃圾收集
我可以事先在適當的時間強制調用GC,但在對該想法進行一些研究后,我發現這很可能是一個壞主意和/或代碼中其他問題的跡象。
使用Hide()方法
雖然這種方法對於任何游戲都是必不可少的,但是必須明確地調用Hide()
每個可繪制對象都是乏味的並且給出了更多的錯誤空間。 此外, 什么時候應該調用所有這些Hide()
? 我也不能依賴於及時收集的父對象,因此將它們放在Finalizer
並不能解決問題。
實現IDisposable
與上面類似, using
語句的替代using
(我不知道在哪里放置,因為對象需要存活直到父母超出范圍)。
我能想到的解決方案似乎都沒有適當地解決這個問題。 我當然錯過了不以這種方式使用弱引用的想法,但是如果找不到可以在當前狀態下使用游戲的適當解決方案,則必須考慮這樣做。 所有這些歸結為一些相關的問題:
這是強制垃圾收集的合適用例嗎?
如果沒有,我怎么能確定一個對象是否是由於當GC下次運行時要收集的?
有沒有辦法在對象的最后一次引用超出范圍(隱式或顯式)時調用對象的方法,而不是等待GC出現?
當然,我對任何可以完全避免這個問題的建議表示感謝。
我打算在這個嘗試答案..
你要找的是“我按照游戲規則死了”的邏輯。 不是“那個對象已經死了,因為垃圾收集器說的那么”邏輯。
為此...你需要將你的想法轉變為這樣的事情:
class DrawableObject {
public bool IsDead { get; set; }
public int Health { get; set; }
// ...
public void GetShot(int amount) {
Health -= amount;
if (Health <= 0)
IsDead = true;
}
}
..然后:
foreach (var drawable in drawables) {
DrawableObject target;
drawable.TryGetTarget(out target);
if(target == null || target.IsDead) {
drawables.Remove(drawable);
}
else {
spriteBatch.Draw(target.Texture, target.Position, target.Rectangle, target.Colour);
}
}
如果它的null
基於你的TryGetXXX
邏輯..或者它被你的游戲邏輯標記為死了..將它從可繪制對象列表中刪除。 讓垃圾收集器隨時清理它。
TLDR:將你的對象標記為死亡,並將你的邏輯基於你自己的“我死了”的旗幟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.