簡體   English   中英

C# - 非靜態類上的靜態事件

[英]C# - Static events on non-static classes

在某些情況下,我非常喜歡靜態事件,但事實上我很少在其他人的代碼中看到它們,這讓我想知道我是否遺漏了一些重要的東西。 我在這個網站上發現了很多關於靜態事件的討論,但是大多數都討論了我不感興趣的情況(比如靜態類)或者我不想考慮使用它們的情況。

感興趣的是,我可能有東西,並長期居住“經理”對象,它反應在這些情況下的東西的一個實例很多情況下的情況。 一個非常簡單的例子來說明我的意思:

public class God {

    //the list of followers is really big and changes all the time, 
    //it seems like a waste of time to
    //register/unregister events for each and every one...  
    readonly List<Believer> Believers = new List<Believer>();

    God() {
        //...so instead let's have a static event and listen to that
        Believer.Prayed += this.Believer_Prayed;
    }

    void Believer_Prayed(Believer believer, string prayer) {
        //whatever
    }
}

public class Believer {

    public static event Action<Believer, string> Prayed;

    void Pray() {
        if (Prayed != null) {
            Prayed(this, "can i have stuff, please");
        }
    }
}

對我來說,這看起來比一個實例事件更清晰,更簡單的解決方案,我也不必監視信徒集合中的變化。 如果Believer類可以“看到”God-type類,我有時會使用NotifyGodOfPrayer()方法(這是幾個類似問題中的首選答案),但是Believer類型的類通常是“模型” - 我不能或不想直接訪問神級的組件。

這種方法有什么實際缺點嗎?

編輯:感謝所有已經花時間回答的人。 我的例子可能不好,所以我想澄清一下我的問題:

如果我在這種情況下使用這種靜態事件

  • 我確信只會有一個subscriber-object實例
  • 只要應用程序正在運行,就可以保證存在
  • 我正在觀看的實例數量巨大

那么我不知道這種方法存在潛在的問題嗎?

除非這個問題的答案是肯定的,否則我並不是真的在尋找替代實現,盡管我非常感謝所有想要提供幫助的人。 我不是在尋找最漂亮的解決方案(我必須將這個獎項提供給我自己的版本只是為了簡短易讀和維護:)

了解事件的一個重要事項是,它們會導致掛鈎事件的對象在事件所有者被垃圾收集之前不被垃圾收集,或者直到事件處理程序被取消掛鈎。

把它放到你的例子中,如果你有一個有多神的多神教神殿,你在那里提升和降級諸如

new God("Svarog");
new God("Svantevit");
new God("Perun");

當他們與Believer.Prayed相連時,眾神會留在你的RAM中。 Believer.Prayed 這會導致你的應用程序泄露神。


我也會評論設計決策,但我明白你所做的例子可能不是你真實場景的最佳副本。

對我來說,不要創造從GodBeliever依賴,並使用事件似乎更合理。 好的方法是創建一個站在信徒和神之間的事件聚合器。 例如:

public interface IPrayerAggregator
{
    void Pray(Believer believer, string prayer);
    void RegisterGod(God god);
}

// god does
prayerAggregator.RegisterGod(this);
// believer does
prayerAggregator.Pray(this, "For the victory!");

在調用Pray方法時,事件聚合器依次調用God類的適當方法。 要管理引用並避免內存泄漏,您可以創建UnregisterGod方法或在諸如的弱引用集合中保存神

public class Priest : IPrayerAggregator
{
    private List<WeakReference> _gods;

    public void Pray(Believer believer, string prayer)
    {
        foreach (WeakReference godRef in _gods) {
            God god = godRef.Target as God;
            if (god != null)
                god.SomeonePrayed(believer, prayer);
            else
                _gods.Remove(godRef);
        }
    }

    public void RegisterGod(God god)
    {
        _gods.Add(new WeakReference(god, false));
    }
}

快速提示:臨時存儲事件委托,因為偵聽器可能會取消其事件處理程序

void Pray() {
    var handler = Prayed;
    if (handler != null) {
        handler(this, "can i have stuff, please");
    }
}

編輯

考慮到你添加了關於你的場景(大量的事件調用者,常量和單個事件觀察者)的細節,我認為你選擇了正確的場景,純粹出於效率原因。 它創建了最少的內存和CPU開銷。 我不會采用這種方法,但對於你所描述的靜態事件,我可能會采取非常實用的解決方案。

我看到的一個缺點是控制流程。 如果您的事件監聽器是按照您所說的單個實例創建的,那么我將利用單身(反)模式並直接從Believer調用God方法。

God.Instance.Pray(this, "For the victory!");
//or
godInstance.Pray(this, "For the victory!");

為什么? 因為那時你可以更精細地控制執行祈禱的動作。 如果你決定將Believer子類Believer一種在某些日子里沒有祈禱的特殊類型,那么你就可以控制它。

我實際上認為having an instance even會更清晰,更具可讀性。
查看它更簡單,因為一個實例正在捕食,所以他的祈禱事件會被觸發。 而且我沒有看到螞蟻的缺點。 我不認為monitor changes不是監視靜態事件的喧囂。 但是正確的方法......

監控列表:
將列表更改為ObservableCollection (並查看NotifyCollectionChangedEventArgs )。
監控它:

public class God {

    readonly ObservableCollection<Believer> Believers = new ObservableCollection<Believer>();

    public God() {
        Believers  = new ObservableCollection<T>();
        Believers.CollectionChanged += BelieversListChanged;
    }

    private void BelieversListChanged(object sender, NotifyCollectionChangedEventArgs args) {

        if ((e.Action == NotifyCollectionChangedAction.Remove || e.Action ==     NotifyCollectionChangedAction.Replace) && e.OldItems != null)
        {
            foreach (var oldItem in e.OldItems)
            {
                var bel= (Believer)e.oldItem;               
                bel.Prayed -= Believer_Prayed; 
            }
        }

        if((e.Action==NotifyCollectionChangedAction.Add ||               e.Action==NotifyCollectionChangedAction.Replace) && e.NewItems!=null)
            {
                foreach(var newItem in e.NewItems)
                {
                   foreach (var oldItem in e.OldItems)
                {
                    var bel= (Believer)e.newItem;               
                    bel.Prayed += Believer_Prayed; 
                }
            }
        }
    }

    void Believer_Prayed(Believer believer, string prayer) {
        //whatever
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM