One important thing to know about events is that they call objects that are attached to the event so as not to collect garbage until the owner of the event is garbage collected or until the event handler is detached.
To give it as an example, if you have a polytheistic pantheon with many gods, where you promote and omit gods such as
new God("Svarog"); new God("Svantevit"); new God("Perun");
the gods would remain in your RAM as long as they are tied to Believer.Prayed . This would cause your application to leak gods.
I will also comment on the design decision, but I understand that the example you made may not be the best copy of your real scenario.
It seems more reasonable to me not to create dependence on God to Believer , but to use events. A good approach would be to create an aggregator of events that will stand between believers and gods. For example:
public interface IPrayerAggregator { void Pray(Believer believer, string prayer); void RegisterGod(God god); }
When calling the Pray method, the event aggregator calls the corresponding method of the God class in turn. To manage links and avoid memory leaks, you can create an UnregisterGod method or keep the gods in a collection of weak links such as
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)); } }
Quick Tip: Temporarily keep the event delegate as listeners can cancel their event handlers
void Pray() { var handler = Prayed; if (handler != null) { handler(this, "can i have stuff, please"); } }
Edit
Keeping in mind the details that you added about your scenario (a huge number of event counters, a constant and single-ended observer of events), I think you have chosen the right scenario, solely for reasons of efficiency. It creates the smallest memory and processor overhead. I would not use this approach at all, but for the scenario that you described, a static event is a very pragmatic decision that I can make.
One drawback that I see is the flow of control. If your event listener is created in one instance, as you say, I would use the singleton (anti) pattern and call the God method from Believer directly.
God.Instance.Pray(this, "For the victory!"); //or godInstance.Pray(this, "For the victory!");
Why? Because then you get more competent control over the action of prayer. If you decide that you need to subclass Believer into a special kind that does not pray on certain days, then you would control it.