Serialising my class is failing because of an eventhandler - c#

I wasn't expecting to come across this error. I imagine I'm doing something wrong somewhere else.
I have an MVVM application.
My model can serialise its self using a BinaryFormatter. This was working fine.
Today I added in an event handler to my model, and the viewmodel that contains the model subscribes to this event.
Now when I try and serialise the model I get an error because my viewmodel isn't serialisable (by design).
I am sure it's down to the subscription to the event, because I've removed the subscription (and only that) and serialisation works again.
I can't apply the [NonSerialized] attribute to the handler because it's not a field.
It there a way around this issue?

you can do this:
[field:NonSerialized]
public event EventHandler MyEvent;

You can make the event a field like this:
[NonSerialized]
private EventHandler _eventHandler;
public event EventHandler MyEvent
{
add { _eventHandler += value; }
remove { _eventHandler -= value; }
}

I don't know how useful this is, but...
...extending what Pieter mentioned, you can also have mutliple delegate handlers wrapped into the same event, so you could (theoretically) make your event, in effect, both serializable and non-serializable by doing something like this:
[NonSerialized]
private EventHandler _nonSerializableeventHandler;
private EventHandler _eventHandler;
public event EventHandler MyEvent
{
add
{
if (value.Method.DeclaringType.IsSerializable)
_eventHandler += value;
else
_nonSerializableeventHandler += value;
}
remove
{
{
if (value.Method.DeclaringType.IsSerializable)
_eventHandler -= value;
else
_nonSerializableeventHandler -= value;
}
}
}

Related

Why can´t we raise event with accessors?

Why can´t we raise an event with a custom implementation, while it is possible without them? See this code:
public class Program
{
private EventHandler myEvent;
public event EventHandler MyEvent
{
add { myEvent += value; }
remove { myEvent -= value; }
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
target.MyEvent(null, null); // ERROR CS0079
target.AnotherEvent(null, null); // compiles
}
}
You see both events are declared within my class. While target.AnotherEvent(...) compiles just fine, target.MyEvent(...) does not:
The Event MyEvent can only appear on the left hand side of += or -=.
I Know an event is just a delegate with an add- and remove-method. So AnotherEvent is translated by the compiler to an add- and a remove-method:
private EventHandler _AnotherEvent;
public event EventHandler AnotherEvent
{
add { _AnotherEvent += value; }
remove { _AnotherEvent -= value; }
}
So I assume the call to AnotherEvent is replaced by the compiler to a call to the private delegate, which was _AnotherEvent(...).
Did I get this right? Are there any docs about why the second call works while the former does not? Or at least any description about what the compiler does here?
When an auto event is used public event EventHandler AnotherEvent;. The compiler will create a field (and some methods) for it and invoking is done on that field. So the public event does not exists anymore. It's syntactic sugar.
So invoking a non-auto event is not possible. Because it isn't found in the compiled code. It's replaced by add_, remove_ methods. You can only invoke on the private field (which is generated)
This explains why you cannot invoke an event outside the class instance.
It doesn't work because there is simply now way to get the actual invokeable event handler. As you have noted, there is just an add and remove, not a get.
The generated code for the event handler is:
.event [mscorlib]System.EventHandler MyEvent
{
.addon instance void ConsoleApp1.Program::add_MyEvent(class [mscorlib]System.EventHandler)
.removeon instance void ConsoleApp1.Program::remove_MyEvent(class [mscorlib]System.EventHandler)
} // end of event Program::MyEvent
It adds two method references, one for add and one for remove. If you look at it, how would it know what method to invoke? What if add and remove are much more complex than they are now? There is just no way to know for sure what event handler to call.
It's syntactical sugar. That you can call AnotherEvent like the backing field is a convenience provided by the compiler (AnotherEvent is a so-called field-like event). Once you add your own accessors, the event declaration ceases to be a field-like event and has to be invoked through its backing field.
See the relevant part of the C# Language Specification:
Field-like events
Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be
used in this way, an event must not be abstract or extern, and must
not explicitly include event_accessor_declarations. Such an event can
be used in any context that permits a field. The field contains a
delegate (Delegates) which refers to the list of event handlers that
have been added to the event. If no event handlers have been added,
the field contains null.
(emphasis mine)
It is recommended that you lock the event before you add or remove a new event handler method.
saying that, have a look on this piece of code:
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
The reason public event EventHandler AnotherEvent; works is because When no custom event accessors are supplied in your code, the compiler will add them automatically.
Follow this doc, How to: Implement Custom Event Accessors in order to get more details about the proper implementation and this post for another source.
Regarding the implementation:
private EventHandler myEvent;
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
var myEvent = target.MyEvent;
myEvent?.Invoke(EventArgs.Empty, EventArgs.Empty);
target.AnotherEvent(null, null);
}
Edit to explain the implementation:
var myEvent = target.MyEvent;
With an explicit event, you have to provide your own backing store - either a delegate field or something like EventHandlerList, so we just go with var here.

Best practice in declaring events in C#

I know the following two methods work, but I wonder if one is better in terms of performance / maintenance / whatever.
The short way:
public event EventHandler MyEvent;
The long way:
private EventHandler _myEvent;
public event EventHandler MyEvent
{
add { _myEvent += value; }
remove { _myEvent -= value; }
}
The long way seems similar to encapsulating members with properties, which is indeed a good practice. But does this apply to event handlers?
In this case, the argument of "good practice" is a little tricker; the first is a "field-like event"; you note:
The long way seems similar to encapsulating members with properties,
but: this is encapsulated (behind add/remove) either way; so by comparison to properties, it is really the difference between:
public int Foo {get;set;}
and
private int foo;
public int Foo {
get { return foo; }
set { foo = value; }
}
In which case I would say "use the first one unless you have an actual reason not to" - it is still hidden behind accessors. Additionally, it is important to note that your second example is not what a field-like event (the first example) expands to : the compiler adds thread-safety into the mix. So: I would say use the first sample:
public event EventHandler MyEvent;
Note that the "how" for the thread-safety depends on which compiler version (and indeed, which specification) you use. In recent Microsoft C# compilers, it does this with Interlocked operations (CompareExchange etc), so it does not require a dedicated private synchronization object.
The first way does exactly the same underneath with creating private EventHandler with the name MyEvent. When it's accessed within the class event handler is returned (i.e. no problem with calling delegate) when it's called outside of class (myClassInstance.MyEvent += SomeHandler/myClassInstance.MyEvent -= SomeHandler) Add/Remove methods are called respectively. And these methods are the same (except they add thread-safety) as those you've written in the second way.
So why do you want to write more code when you actually don't need it?
To check what Marc Gravel mean i tried the following code:
public event EventHandler MyEventShortWay;
private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
add { _myEvent += value; }
remove { _myEvent -= value; }
}
I was surprised by what was generated (I edited the decompiled variable name) :
private EventHandler _myEventShortWay;
public event EventHandler MyEventShortWay
{
add
{
EventHandler handler2;
EventHandler myEventShortWay = this._myEventShortWay;
do
{
handler2 = myEventShortWay;
EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
}
while (myEventShortWay != handler2);
}
remove
{
EventHandler handler2;
EventHandler myEventShortWay = this._myEventShortWay;
do
{
handler2 = myEventShortWay;
EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
}
while (myEventShortWay != handler2);
}
}
private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
add
{
this._myEvent = (EventHandler) Delegate.Combine(this._myEvent, value);
}
remove
{
this._myEvent = (EventHandler)Delegate.Remove(this._myEvent, value);
}
}

Is it possible to subscribe to event subscriptions in C#?

If I have an event like this:
public delegate void MyEventHandler(object sender, EventArgs e);
public event MyEventHandler MyEvent;
And adds an eventhandler like this:
MyEvent += MyEventHandlerMethod;
... is it then possible to register this somehow? In other words - is it possible to have something like:
MyEvent.OnSubscribe += MySubscriptionHandler;
Similar to auto-implemented properties, events are auto-implemented by default as well.
You can expand the declaration of an event as follows:
public event MyEventHandler MyEvent
{
add
{
...
}
remove
{
...
}
}
See, for example, How to: Use a Dictionary to Store Event Instances (C# Programming Guide)
See Events get a little overhaul in C# 4, Part I: Locks for how auto-implemented events differ between C# 3 and C# 4.
It is possible to declare the event accessors specifically, i.e., the add and remove accessors.
Doing so makes it possible to do custom logic when new event handlers are added.
When you define your events, you can actually use the longer format to execute more code when people attach or remove themselves from your events.
Check out the info on the add and remove keywords.
I guess, you are looking for event accessors. Way to customizing the references to the subscribers. Here is how you can do it
public class TestClass
{
private event EventHandler UnderlyingEvent;
public event EventHandler TestEvent
{
add
{
UnderlyingEvent += value;
}
remove
{
UnderlyingEvent -= value;
}
}
}
For more information, please visit this article
http://msdn.microsoft.com/en-us/magazine/cc163533.aspx
It's possible if you declare your custom event, like this pseudocode:
class MyClass
{
public event EventHandler MyEvent
{
add { //someone subscribed to this event ! }
remove { //someone unsubscribed from this event ! }
}
...
}

-event- can only appear on the left hand side of += or -=

I have an event in a loop. I am trying to prevent the same method being added to an event more than once. I've implemented the add and remove accessors.
However, I get an error stating that:
ItemsProcessed can only appear on the left hand side of += or -=
When I try to call them, even within the same class.
ItemsProcessed(this, new EventArgs()); // Produces error
public event EventHandler ItemsProcessed
{
add
{
ItemsProcessed -= value;
ItemsProcessed += value;
}
remove
{
ItemsProcessed -= value;
}
}
With an explicit event, you need to provide your own backing store - either a delegate field or something like EventHandlerList. The current code is recursive. Try:
private EventHandler itemsProcessed;
public event EventHandler ItemsProcessed
{
add
{
itemsProcessed-= value;
itemsProcessed+= value;
}
remove
{
itemsProcessed-= value;
}
}
Then (and noting I'm being a little cautious about the "about to turn null" edge-case re threading):
var snapshot = itemsProcessed;
if(snapshot != null) snapshot(this, EventArgs.Empty);
With more recent C# versions, this can be simplified:
itemsProcessed?.Invoke(this, EventArgs.Empty);
I can't tell from your post if you are trying to raise the event from a derived class or not, but one thing I've found is that you can't define an event in a base class and then raise it (directly) in a derived class, for some reason that isn't real clear to me yet.
So I define protected functions in base classes to raise events (that are defined in those base classes), like this:
// The signature for a handler of the ProgressStarted event.
// title: The title/label for a progress dialog/bar.
// total: The max progress value.
public delegate void ProgressStartedType(string title, int total);
// Raised when progress on a potentially long running process is started.
public event ProgressStartedType ProgressStarted;
// Used from derived classes to raise ProgressStarted.
protected void RaiseProgressStarted(string title, int total) {
if (ProgressStarted != null) ProgressStarted(title, total);
}
Then in the derived class, I call RaiseProgressStarted(title, total) instead of calling ProgressStarted(title, total).
It seems like kind of the long way around. Maybe someone else knows of a better way around this problem.
It seems that if you implement the EventHandler explicitly, you can't refer to the 'Property' when firing the event. You must refer to the backing store.
What error? I guess its stack overflow error, because you are calling add and remove on yourserlf (same event). Also you cannot raise event ACCESSOR.
Valid way to do this is to create backing private event, that will be added and removed to from public accessor, and you should raise this private event.
Dang, minute late.

Is it possible for a class to respond when a calling class subscribes to one of its events

I have a windows form with a button on it and I only want that button to be visible, if the form that calls it, has subscribed to one of the forms custom events.
I know I can check whether myEvent == null, but what if the event is subscribed to after the form has been loaded?
Is this possible?
(Perhaps just a timer on the form, continually checking whether the event is null?? (sounds messy though)
If it's a custom event, you can put the overrides on where the client subscribes / unsubscribes:
private EventHandler _customEventDelegate;
public event EventHandler MyCustomEvent
{
add
{
bool wasNull = (_customEventDelegate == null);
_customEventDelegate += value;
if(wasNull)
{
this.ChangeButtonVisibility(true);
}
}
remove
{
_customEventDelegate -= value;
if(_customEventDelegate == null)
{
this.ChangeButtonVisibility(false);
}
}
}
Just like properties events have associated methods as well so:
public event EventHandler MyEvent {
add {
// do something
}
remove {
// do something
}
}

Categories

Resources