Negative Aspects/Bad Practice of Static Event in C# - c#

I reuse the code below a lot when I create events that will be used in different areas of an application. I find it really helpful and it makes events very easy to follow in the code. Is there any reason why this could be a bad idea? This is a bit broad, but basically is there a reason not to do this?
Event classes:
public delegate void FocusEventHandler(object source, FocusEventArgs e);
class FocusEvent
{
public static event FocusEventHandler focusEvent;
public static void Focus(bool status)
{
focusEvent(null, new FocusEventArgs(status));
}
}
public class FocusEventArgs : EventArgs
{
public bool Focused { get; set; }
public FocusEventArgs(bool f)
{
Focused = f;
}
}
So to fire the event, all I need is:
FocusEvent.Focus(false);
Thanks guys. This helps a lot. I really need to read up on memory usage.

The single biggest problem with static events is that you need to be really careful about unsubscribing from them. With an instance event, if you don't unsubscribe then you might end up keeping part of a graph artificially alive until the object with the event is released and is unreachable (making all the subscribers unreachable) - however, a static event never becomes unreachable. This means that any subscribers that don't unsubscribe will never be unreachable, and will never be garbage collected.

A few years back, I worked on a large-scale Windows app that used static events. While investigating some memory usage issues, I discovered that no forms in the entire application were ever garbage collected. Pretty much every form subscribed to a static event, but never unsubscribed, causing them to stick around forever.
So yeah, the main reason not to do this is that you'll inevitably forget to unsubscribe from the event at some point, causing things to stick around for the lifetime of the application.

Related

Scoped service becomes singleton. How to debug? [duplicate]

I want to know can we declare the events as static if yes why and application of such declaration.
Sample please as seeing is believing
You can create static events. You use them the same way as a normal event, except that it's used in a static context within the class.
public class MyClass
{
public static event EventHandler MyEvent;
private static void RaiseEvent()
{
MyEvent?.Invoke(typeof(MyClass), EventArgs.Empty);
}
}
That being said, there are many issues with static events. You must take extra care to unsubscribe your objects from static events, since a subscription to a static event will root your subscribing instance, and prevent the garbage collector from ever collecting it.
Also, I've found that most cases where I'd want to make static events, I tend to learn towards using a standard event on a Singleton instead. This handles the same scenarios as a static event, but is (IMO) more obvious that you're subscribing to a "global" level instance.
Yes, you can. See, for example, Application.ApplicationExit. Note, however, the warnings on that page about memory leaks when attaching to static events; that applies to all static events.
There's nothing magical about when you use them: when you need to provide an event for a static class or an event that deals exclusively with static data and it makes sense to implement it this way.
Yes, you can declare an event as static. You use them the same way you would use them if they were instance events, but you access the event name in a static way (i.e. ClassName.EventName, rather than variableName.EventName).
Now... do you want static events? That's highly debatable. I personally would say no, since static anything creates difficulties in testing and should thus be avoided whenever possible.
But it's certainly possible.
public delegate void SomeEventDelegate();
public class SomeClass
{
public static event SomeEventDelegate SomeEvent;
}

Would subscribing to my own C# event create a memory leak?

If a base class publishes a C# event and a derived class subscribes to it -- i.e. subscribes to itself --. Will the event subscription prevent the object from being garbage collected? Or is the garbage collector smart enough to detect such circular reference situations.
At first glance, it seems like it should but I'm pretty sure I've seen control code that does this. This is such a fundamental question I can't believe I've never looked into it before.
Edit: For Juan R. I mean something like this. (Never compiled this code, just typed it off the top of my head so I might have typos/errors)
public class Base
{
public event EventHandler<double> ValueChanged;
}
public class Derived : Base
{
public Derived()
{
// Will this prevent my object from being collected?
ValueChanged += OnValueChanged;
}
private void OnValueChanged(object sender, double v)
{
}
}
An object subscribing to its own event will not cause a memory leak for the simple reason that the CLR GC is based on reachability, not reference counting. If the object is reachable from a GC root, then it was not eligible for GC anyway. And if it's not reachable, then a self-reference does not make it reachable. There is nothing special about events with regard to GCing circular references.

Garbage cleanup on c# events [duplicate]

This question already has answers here:
Is it necessary to explicitly remove event handlers in C#
(2 answers)
Closed 5 years ago.
Let's say I have a c# class which can be subscribed to like so:
public class Emitter {
public delegate void EmitAction(Emitter emitter);
public event EmitAction OnEmitted;
public void DoEmit() {
if(OnEmitted != null)
OnEmitted(this);
}
}
...and another class that makes use of it:
public class EmissionUser {
public void SomeFunction() {
Emitter em = new Emitter();
em.OnEmitted += HandleIt;
em.DoEmit();
}
public void HandleIt(Emitter em) {
//I could just do em -= HandleIt, but is there any point?
}
}
I know that for code cleanliness and avoiding memory leaks, it's always good have one unsubscribe for every subscribe when using events. However in a case like this, the Emitter instance is created locally in SomeFunction(), and not held in memory for too long, so I'm guessing the event subscription is destroyed with the local instance.
Is it still a good idea to unsubscribe in the handler? If so why?
Well, em is a local instance and will get destroyed with the end of HandleIt. You can choose to leave it like that if you are not going to use it anywhere else.
But if you have the reference of it somewhere else, or going to create one in future, it would create problems. Also, finding root cause of bugs related to events is tricky.
I noticed that you are passing the emitter reference. Someone can again use the same reference to call different method or raise an event within handleIt.
So, I would suggest you to do it, just for the sake of future-proofing the code.
Yes you don't need to unsubscribe because as you said the em variable destroyed after the SomeFuction returned, and nobody else has reference to this object so the garbage collector can clean it up.

Does Dispose() get called if my app crashes?

I have a scenario where on application crash, I have to clear certain registry keys. I am trying to use Dispose() pattern for it. in case of application crash during garbage collection does the Dispose gets called to clear the registry???
Is there any other pattern to do such activities? I can not use Unhandled application handler as the code I want to call is not referenced directly by the Main application. I could use reflection but not sure if that's the right pattern.
any advise or experience in this matter will be really appreciated.
It sounds like you want to add an event handler to the AppDomain.UnhandledException event, do some processing (writing to the registry in this case) and then let the program die.
Assuming that you're not doing anything odd like loading your library into a different AppDomain you should be able to hook this from your library in a variety of ways. I've used a static constructor for this in the past and to hook the AssemblyResolve event from a library.
Something like this:
public static class CrashHandler
{
public static bool Initialized { get; private set; }
[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlAppDomain)]
static CrashHandler()
{
AppDomain.CurrentDomain.UnhandleException += crash_handler;
Initialized = true;
}
static void crash_handler(object sender, UnhandledExceptionEventArgs args)
{
// do your thing here
}
}
In order to get this to actually fire you need to read the Initialized value somewhere at least once. Add it to the constructor of one of your library objects that you can be sure will be instantiated early.

Destructor implemented via event

I have several objects in our framework, that by the requirement need to provide event ObjectTerminated. The user of the framework can subscribe to this event and clean-up some unmanaged stuff, that he is using. These objects are designed to exist the whole life time of the application, and I'm not controlling their life. You can think of them as an array of singletons.
I want to write code like this:
class SomeWorkflowControlObject
{
public event EventHandler<> ObjectTerminated;
~SomeWorkflowControlObject()
{
if (ObjectTerminated != null) ObjectTerminated(this, null);
}
}
I am not sure, am I allowed to do that. What could go possibly wrong with such solution?
Updated:
What about Process.GetCurrentProcess().Exited ? Can I use it in such manner?
You should not do this. Basically, destructors do not exist in C#. What you have written is a finalizer, and the only thing a finalizer should ever do is to free unmanaged resources.
You are not allowed to access any other managed object at all, since the garbage collector might already have removed it. I do not think your null check is a sufficient guard against this situation; that object reference might still point to your (event) delegate, even if it's already gone.
So in short, don't do this.
Alternatives:
Subscribe to the Application.ApplicationExit event if you have a Windows Forms application.
You might want to consider implementing the IDisposable interface instead and then do something like this:
public class SomethingVeryLongLived : IDisposable
{
…
}
…
public static void Main()
{
using (var sth = new SomethingVeryLongLived(…))
{
Application.Run(new SomeForm(…));
} // <-- at this point, foo.Dispose() is guaranteed to be called.
}
Take note that even in the case of using IDisposable, it's probably not a good idea / design to trigger an event inside the object that is getting disposed, since disposed objects should no longer be accessed.
For this very reason, I would recommend you do the following:
Use a try…finally block:
public static void Main()
{
var sth = new SomethingVeryLongLived(…);
try
{
Application.Run(new SomeForm(…));
}
finally
{
SomethingVeryLongLived.Terminate();
}
}
This would seem best to me because you are not abusing the IDisposable interface, and it's very clear what the code does... there's no hidden meaning.
I believe the design of that framework is inherently flawed. Let me explain:
1. [...] several objects in our framework, that by the requirement need to provide event ObjectTerminated.
This doesn't make sense. If an object has been terminated, as the event's name suggests, then I would assume that it is already gone and that I can no longer access it. This raises two questions:
How does something dead trigger an event? It's like a corpse talking to you from its grave, "I am dead." Do you really want this?
Why would anyone else be interested in reacting to such an event, if the event sender is no longer supposed to be there? What is there to clean up after the corpse has already been buried?
2. I'm not controlling their life.
Who is controlling their lifetime, then? Why isn't it their responsibility to do, or trigger, the necessary clean up work at the appropriate moment? Let me further elaborate on this very point:
3. [...] can subscribe to this event and clean-up some unmanaged stuff [...]
Where is this unmanaged stuff, and which object is responsible for handling it? If it is your own object, then why doesn't your object dispose of it — why do you instead want to trigger an event, so that someone else can dispose of the stuff? It's like me carrying out my neighbour's garbage, instead of him doing it himself. (I'm not talking about an old lady there.)
Your class would make much more sense if it looked like this:
class SomeWorkflowControlObject : IDisposable
{
// the following event doesn't make sense, sorry.
// public event EventHandler<> ObjectTerminated;
private IntPtr _handleToUnmanagedResource;
~SomeWorkflowControlObject()
{
Dispose(explicitly: false);
}
public void Dispose()
{
Dispose(explicitly: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool explicitly)
{
if (explicitly)
{
// free managed resources here; perhaps trigger an event 'Disposing'.
}
DisposeUnmanagedResource(_handleToUnmanagedResource);
}
}
That is, it is a wrapper around some unmanaged resource, for whose disposal it is responsible itself, and noone else. Thus, there is no longer a need to trigger an event, such that someone else can dispose the unmanaged resource, which should be hidden inside your object anyway.

Categories