Serialization - Pesky VB's Event implementation.

C

Codemonkey

Heya All,

Sorry, but I think it's about time for a monkey-ramble.

I've just had enough of trying to serialize even simple objects with VB. A
simple task you may think - stick the <Serialized()> attribute on the class
and away you go. As Homer would say - "D'Oh"

The root of my problem lies in the way VB implements Events and the fact
that you can't apply the <NonSerialized> attribute to the little rascals.
The result of this is that when you serialize ObjectA that has an event
EventX being handled by a method in ObjectB, ObjectB gets serialized right
along with ObjectA.

If you don't believe me, go ahead and try it. Create a serializable class
with an event and some private fields. Create a form an declare an instance
of the class and handle the event (with withevents or addhandler - doesn't
matter). Now try and serialize the instance of the class - you'll get a
serialization exception because the form (not the class you're trying to
serialize) isn't serializable!

Fair enough, you may say. This shouldn't be a big problem - just remove
event handlers before serializing. Why should I have to do this? I can't
even do it reliably (because I have no way of telling who has attached to my
events - it could be some client that I have no control over).

Another problem becomes apparent if you have a custom collection of objects
(say Trigger objects that fire an event periodically). The Collection of
triggers has it's own event which is raised when any of the triggers it
contains fires. A simple (but admittedly probably not the best) way to
implement the collection would be to use addhandler to attach to a trigger's
event when adding it to the collection. Now, guess what happens when you try
and serialize the collection - it works! WooHoo!. Now try and deserialize
it. Again "D'Oh". This time you get an exception because you can't
deserialize a delegate to a private method for security reasons!

In my travels I've had many suggestions about how to get around this and
have come up with some solutions on my own. Here are a few of them and their
pros and cons:

1) Implement ISerializable and don't serialize the events.
Pros: It Works
Cons: Too much work - have to change the GetObjectData method and
Constructor every time I add a field that is to be serialized.


2) Implement an ISerializationSurrogate to strip out the events:
Pros: Dunno
Cons: Pretty complicated to do because the Binary Formatter and Soap
Formatter don't allow you to specify surrogates, so you end up re-writing
them too.

3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Pros: It works
Cons: It's a hack

4) Implement the events in a C# Base class
Pros: You can specify the [NonSerialized] attribute to the event
Cons: Your logic is spread across two projects and two languages.


As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?


Thanks for putting up with this monkey-ramble. I'm off to learn C# ;)

Cheers,

Trev.
 
J

Jay B. Harlow [MVP - Outlook]

Codemonkey,
As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?
As soon as they say you cannot, someone will come up with a valid reason ;-)
1) Implement ISerializable and don't serialize the events.
This is the one I've been using as I needed ISerializable for other purposes
and lucked out on the event part of it ;-)
2) Implement an ISerializationSurrogate to strip out the events:
I consider this a variation of #1, only in a second class.
3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Reflection or SerializationServices? I was under the impression you can use
SerializationServices from the current class. Granted you may need to trim
the array that SerializationServices.GetSerializableMembers returned,
however I would think that would be easier then implementing all the logic
yourself...

Hope this helps,
Jay

Codemonkey said:
Heya All,

Sorry, but I think it's about time for a monkey-ramble.

I've just had enough of trying to serialize even simple objects with VB. A
simple task you may think - stick the <Serialized()> attribute on the class
and away you go. As Homer would say - "D'Oh"

The root of my problem lies in the way VB implements Events and the fact
that you can't apply the <NonSerialized> attribute to the little rascals.
The result of this is that when you serialize ObjectA that has an event
EventX being handled by a method in ObjectB, ObjectB gets serialized right
along with ObjectA.

If you don't believe me, go ahead and try it. Create a serializable class
with an event and some private fields. Create a form an declare an instance
of the class and handle the event (with withevents or addhandler - doesn't
matter). Now try and serialize the instance of the class - you'll get a
serialization exception because the form (not the class you're trying to
serialize) isn't serializable!

Fair enough, you may say. This shouldn't be a big problem - just remove
event handlers before serializing. Why should I have to do this? I can't
even do it reliably (because I have no way of telling who has attached to my
events - it could be some client that I have no control over).

Another problem becomes apparent if you have a custom collection of objects
(say Trigger objects that fire an event periodically). The Collection of
triggers has it's own event which is raised when any of the triggers it
contains fires. A simple (but admittedly probably not the best) way to
implement the collection would be to use addhandler to attach to a trigger's
event when adding it to the collection. Now, guess what happens when you try
and serialize the collection - it works! WooHoo!. Now try and deserialize
it. Again "D'Oh". This time you get an exception because you can't
deserialize a delegate to a private method for security reasons!

In my travels I've had many suggestions about how to get around this and
have come up with some solutions on my own. Here are a few of them and their
pros and cons:

1) Implement ISerializable and don't serialize the events.
Pros: It Works
Cons: Too much work - have to change the GetObjectData method and
Constructor every time I add a field that is to be serialized.


2) Implement an ISerializationSurrogate to strip out the events:
Pros: Dunno
Cons: Pretty complicated to do because the Binary Formatter and Soap
Formatter don't allow you to specify surrogates, so you end up re-writing
them too.

3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Pros: It works
Cons: It's a hack

4) Implement the events in a C# Base class
Pros: You can specify the [NonSerialized] attribute to the event
Cons: Your logic is spread across two projects and two languages.


As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?


Thanks for putting up with this monkey-ramble. I'm off to learn C# ;)

Cheers,

Trev.
 
C

Crirus

Yeah, I noticed that too...
I have a class that need to be serialised, and another class with events
not to be serialised
I have a reference of the class with events in first class and I have to
detach any event handler before serialisation ... the opposite to your
issue.... ugly thing


--
Cheers,
Crirus

------------------------------
If work were a good thing, the boss would take it all from you

------------------------------

Codemonkey said:
Heya All,

Sorry, but I think it's about time for a monkey-ramble.

I've just had enough of trying to serialize even simple objects with VB. A
simple task you may think - stick the <Serialized()> attribute on the class
and away you go. As Homer would say - "D'Oh"

The root of my problem lies in the way VB implements Events and the fact
that you can't apply the <NonSerialized> attribute to the little rascals.
The result of this is that when you serialize ObjectA that has an event
EventX being handled by a method in ObjectB, ObjectB gets serialized right
along with ObjectA.

If you don't believe me, go ahead and try it. Create a serializable class
with an event and some private fields. Create a form an declare an instance
of the class and handle the event (with withevents or addhandler - doesn't
matter). Now try and serialize the instance of the class - you'll get a
serialization exception because the form (not the class you're trying to
serialize) isn't serializable!

Fair enough, you may say. This shouldn't be a big problem - just remove
event handlers before serializing. Why should I have to do this? I can't
even do it reliably (because I have no way of telling who has attached to my
events - it could be some client that I have no control over).

Another problem becomes apparent if you have a custom collection of objects
(say Trigger objects that fire an event periodically). The Collection of
triggers has it's own event which is raised when any of the triggers it
contains fires. A simple (but admittedly probably not the best) way to
implement the collection would be to use addhandler to attach to a trigger's
event when adding it to the collection. Now, guess what happens when you try
and serialize the collection - it works! WooHoo!. Now try and deserialize
it. Again "D'Oh". This time you get an exception because you can't
deserialize a delegate to a private method for security reasons!

In my travels I've had many suggestions about how to get around this and
have come up with some solutions on my own. Here are a few of them and their
pros and cons:

1) Implement ISerializable and don't serialize the events.
Pros: It Works
Cons: Too much work - have to change the GetObjectData method and
Constructor every time I add a field that is to be serialized.


2) Implement an ISerializationSurrogate to strip out the events:
Pros: Dunno
Cons: Pretty complicated to do because the Binary Formatter and Soap
Formatter don't allow you to specify surrogates, so you end up re-writing
them too.

3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Pros: It works
Cons: It's a hack

4) Implement the events in a C# Base class
Pros: You can specify the [NonSerialized] attribute to the event
Cons: Your logic is spread across two projects and two languages.


As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?


Thanks for putting up with this monkey-ramble. I'm off to learn C# ;)

Cheers,

Trev.
 
P

Peter Huang

Hi CodeMonkey,

This is a great idea for a future product enhancement. I'd recommend that
you forward the recommendation to the Microsoft Wish Program:

Microsoft offers several ways for you to send comments or suggestions about
Microsoft products. If you have suggestions for product enhancements that
you would like to see in future versions of Microsoft products, please
contact us using one of the methods listed later in this article.

Let us know how we can improve our products.

Product Enhancement suggestions can include:

" Improvements on existing products.
" Suggestions for additional features.
" Ways to make products easier to use.

World Wide Web - To send a comment or suggestion via the Web, use one of
the following methods:

" In Internet Explorer 6, click Send Feedback on the Help menu and then
click the link in the Product Suggestion section of the page that appears.
" In Windows XP, click Help and Support on the Start menu. Click Send your
feedback to Microsoft, and then fill out the Product Suggestion page that
appears.
" Visit the following Microsoft Web site: http://www.microsoft.com/ms.htm
" Click Microsoft.com Guide in the upper-right corner of the page and then
click Contact Us . Click the link in the Product Suggestion section of the
page that appears.
" Visit the following Microsoft Product Feedback Web site:
"http://register.microsoft.com/mswish/suggestion.asp" and then complete and
submit the form.

E-mail - To send comments or suggestions via e-mail, use the following
Microsoft Wish Program e-mail address, (e-mail address removed).
FAX - To send comments or suggestions via FAX, use the following Microsoft
FAX number, (425) 936-7329.

Each product suggestion is read by a member of our product feedback team,
classified for easy access, and routed to the product or service team to
drive Microsoft product and/or service improvements. Because we receive an
abundance of suggestions (over 69,000 suggestions a year!) we can't
guarantee that each request makes it into a final product or service. But
we can tell you that each suggestion has been received and is being
reviewed by the team that is most capable of addressing it.

All product or service suggestions received become the sole property of
Microsoft. Should a suggestion be implemented, Microsoft is under no
obligation to provide compensation.


Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
P

Peter Huang

Hi,

If you have concern on this issue ,please post here.

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
C

Crirus

You replyed for me?

Yes, I'm annoyed about the fact that for a class to be serialized, it cant
have mapped event hndlers in a class not serialisable
I whould like to decide myself if a class I design should attempt to
serialise an object that handle my events.
 
C

Codemonkey

2) Implement an ISerializationSurrogate to strip out the events:
I consider this a variation of #1, only in a second class.

Yeah, with the exception that you can't use surrogates with the built in
soap or binary formatter.
As soon as they say you cannot, someone will come up with a valid reason
;-)

Well I have a pretty valid reason for *not* doing it. The option to do it or
not to do it would have been nice. said:
Reflection or SerializationServices? I was under the impression you can use
SerializationServices from the current class. Granted you may need to trim
the array that SerializationServices.GetSerializableMembers returned,
however I would think that would be easier then implementing all the logic
yourself...

D'Oh. Now you tell me! I actually went ahead and used reflection to do it.
It worked out pretty well, but I haven't performance tested it. Basically, I
used the following algorithm to get the serializable fields:

1. Get all the Fields in this object (and derived objects) using reflection
2. Filter out those with <NonSerialized> and delegate types.
3. Add all the values of the fields to the SerializationInfo object.

Guess I was reinventing the wheel ;)

Cheers for listening to the ramble

Trev.
 
C

Codemonkey

I have a reference of the class with events in first class and I have to
detach any event handler before serialisation ...

Good idea. Never though of this myself, but I still don't like my logic
spread over two classes, especially because of an apparent shortfall in the
language (namely <NonSerialized>).

Thanks for the idea,

Trev.
 
C

Codemonkey

Thanks, Peter.
Because we receive an
abundance of suggestions
(over 69,000 suggestions a year!)

Humm. Let me see if I can bring that number up a bit ;)

Trev.
 
C

Codemonkey

I was under the impression you can use
SerializationServices from the current
class. Granted you may need to trim
the array that SerializationServices.GetSerializableMembers

I looked for SerializationServices and couldn't find it. Did you mean
FormatterServices instead?

Looking at the FormatterServices.GetSerializableMembers Method, I guess I
could use it in my serializable class by filtering out delegates. If I get
around to a proper implementation, I'll post a new thread with the source,
just in case others are interested.

Cheers again,

Trev.
 
J

Jay B. Harlow [MVP - Outlook]

Trev,
Yeah, with the exception that you can't use surrogates with the built in
soap or binary formatter.
Can you explain further? The sample in the MSDN mag articles (third article
below, figure 2) uses ISerializationSurrogate with the SOAP formatter! I
would expect the same sample would work with the Binary formatter. Are you
certain you implemented it correctly & got it registered with the surrogate
selector & formatter correctly? I admit I have not played with
ISerializationSurrogate so I cannot say for certain either way. However its
purpose in life is to support the soap & binary formatters. Are you thinking
it doesn't work with the XmlFormatter? As I understand the XmlFormatter does
"its own thing" (too many formatters, not enough clear information).
D'Oh. Now you tell me! I actually went ahead and used reflection to do it.
You have looked at the following three part MSDN mag articles?

http://msdn.microsoft.com/msdnmag/issues/02/04/net/
http://msdn.microsoft.com/msdnmag/issues/02/07/net/
http://msdn.microsoft.com/msdnmag/issues/02/09/net/

They cover lightly cover FormatterServices (not SerializationServices, it
was late), detailed cover ISerializationSurrogate, and mostly cover every
thing else about serialization.

Hope this helps
Jay
 
J

Jay B. Harlow [MVP - Outlook]

Trev,
Yes FormatterServices not SerializationServices, it was late.

See my other post for more details.

Jay
 
C

Codemonkey

It would be nice to get the new version *this* year sometime! :)

Yeah, before I have to renew my MSDN subscription for next year to get it ;)
 
C

Codemonkey

Can you explain further?

Sorry for making such a general assumption. I was referring to my
experiences with Serialization and Remoting with Soap and Binary Formatters.
There was a discussion I started a long time ago in the *.framework.remoting
and *.distributed_apps groups that explained this problem. I can't find all
the articles right now, but try http://tinyurl.com/2pxkp for a start. I seem
to remember that the problem was something about not being able to set the
formatters up to use a surrogate selector within the remoting framework.
Again, sorry for making the generalization about serialization.

You have looked at the following three part MSDN mag articles?

Yeah, you posted those to me before in the thread above, but I totally
forgot about them. Cheers for the reminder.

Trev.
 
J

Jay B. Harlow [MVP - Outlook]

Trev,
That's right Remoting you cannot use surrogates (at least easily). ;-)
Yeah, you posted those to me before in the thread above, but I totally
forgot about them. Cheers for the reminder.
Yep they are my Serialization FAQ, I loose track who I share them with...

Jay

Codemonkey said:
Sorry for making such a general assumption. I was referring to my
experiences with Serialization and Remoting with Soap and Binary Formatters.
There was a discussion I started a long time ago in the *.framework.remoting
and *.distributed_apps groups that explained this problem. I can't find all
the articles right now, but try http://tinyurl.com/2pxkp for a start. I seem
to remember that the problem was something about not being able to set the
formatters up to use a surrogate selector within the remoting framework.
Again, sorry for making the generalization about serialization.



Yeah, you posted those to me before in the thread above, but I totally
forgot about them. Cheers for the reminder.

Trev.
<<snip>>
 
P

Peter Huang

Hi Critus,

So far, I think you may try Codemonkey's suggestions in his original post.

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
T

Trev Hunter

Ok,

I've decided to channel my monkey-rambling energy into providing a
(hopefully) useful article on CodeProject about serialization of VB classes
with events.

Have a look at http://www.codeproject.com/useritems/serializevbclasses.asp

and let me know what you think

Best Regards,

Trev.

Codemonkey said:
Heya All,

Sorry, but I think it's about time for a monkey-ramble.

I've just had enough of trying to serialize even simple objects with VB. A
simple task you may think - stick the <Serialized()> attribute on the class
and away you go. As Homer would say - "D'Oh"

The root of my problem lies in the way VB implements Events and the fact
that you can't apply the <NonSerialized> attribute to the little rascals.
The result of this is that when you serialize ObjectA that has an event
EventX being handled by a method in ObjectB, ObjectB gets serialized right
along with ObjectA.

If you don't believe me, go ahead and try it. Create a serializable class
with an event and some private fields. Create a form an declare an instance
of the class and handle the event (with withevents or addhandler - doesn't
matter). Now try and serialize the instance of the class - you'll get a
serialization exception because the form (not the class you're trying to
serialize) isn't serializable!

Fair enough, you may say. This shouldn't be a big problem - just remove
event handlers before serializing. Why should I have to do this? I can't
even do it reliably (because I have no way of telling who has attached to my
events - it could be some client that I have no control over).

Another problem becomes apparent if you have a custom collection of objects
(say Trigger objects that fire an event periodically). The Collection of
triggers has it's own event which is raised when any of the triggers it
contains fires. A simple (but admittedly probably not the best) way to
implement the collection would be to use addhandler to attach to a trigger's
event when adding it to the collection. Now, guess what happens when you try
and serialize the collection - it works! WooHoo!. Now try and deserialize
it. Again "D'Oh". This time you get an exception because you can't
deserialize a delegate to a private method for security reasons!

In my travels I've had many suggestions about how to get around this and
have come up with some solutions on my own. Here are a few of them and their
pros and cons:

1) Implement ISerializable and don't serialize the events.
Pros: It Works
Cons: Too much work - have to change the GetObjectData method and
Constructor every time I add a field that is to be serialized.


2) Implement an ISerializationSurrogate to strip out the events:
Pros: Dunno
Cons: Pretty complicated to do because the Binary Formatter and Soap
Formatter don't allow you to specify surrogates, so you end up re-writing
them too.

3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Pros: It works
Cons: It's a hack

4) Implement the events in a C# Base class
Pros: You can specify the [NonSerialized] attribute to the event
Cons: Your logic is spread across two projects and two languages.


As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?


Thanks for putting up with this monkey-ramble. I'm off to learn C# ;)

Cheers,

Trev.
 
J

Jay B. Harlow [MVP - Outlook]

Trev,
I'm not so sure that the NonSerialized attribute needs to be fixed as much
as VB.NET needs to support the Field modifier on attributes. Other wise it
looks like a good article...

In C# you use:
[field: NonSerialized]
public event EventHandler NameChanged;

Unfortunately VB.NET only supports Assembly & Module modifiers on attributes

Such as:
<Assembly: NonSerialized>
or
<Module: NonSerialized>

The Field modifier is not supported.

<Field: NonSerialized> causes a syntax error.

Remember the thread from last October?

Hope this helps
Jay

Trev Hunter said:
Ok,

I've decided to channel my monkey-rambling energy into providing a
(hopefully) useful article on CodeProject about serialization of VB classes
with events.

Have a look at http://www.codeproject.com/useritems/serializevbclasses.asp

and let me know what you think

Best Regards,

Trev.

Codemonkey said:
Heya All,

Sorry, but I think it's about time for a monkey-ramble.

I've just had enough of trying to serialize even simple objects with VB. A
simple task you may think - stick the <Serialized()> attribute on the class
and away you go. As Homer would say - "D'Oh"

The root of my problem lies in the way VB implements Events and the fact
that you can't apply the <NonSerialized> attribute to the little rascals.
The result of this is that when you serialize ObjectA that has an event
EventX being handled by a method in ObjectB, ObjectB gets serialized right
along with ObjectA.

If you don't believe me, go ahead and try it. Create a serializable class
with an event and some private fields. Create a form an declare an instance
of the class and handle the event (with withevents or addhandler - doesn't
matter). Now try and serialize the instance of the class - you'll get a
serialization exception because the form (not the class you're trying to
serialize) isn't serializable!

Fair enough, you may say. This shouldn't be a big problem - just remove
event handlers before serializing. Why should I have to do this? I can't
even do it reliably (because I have no way of telling who has attached
to
my
events - it could be some client that I have no control over).

Another problem becomes apparent if you have a custom collection of objects
(say Trigger objects that fire an event periodically). The Collection of
triggers has it's own event which is raised when any of the triggers it
contains fires. A simple (but admittedly probably not the best) way to
implement the collection would be to use addhandler to attach to a trigger's
event when adding it to the collection. Now, guess what happens when you try
and serialize the collection - it works! WooHoo!. Now try and deserialize
it. Again "D'Oh". This time you get an exception because you can't
deserialize a delegate to a private method for security reasons!

In my travels I've had many suggestions about how to get around this and
have come up with some solutions on my own. Here are a few of them and their
pros and cons:

1) Implement ISerializable and don't serialize the events.
Pros: It Works
Cons: Too much work - have to change the GetObjectData method and
Constructor every time I add a field that is to be serialized.


2) Implement an ISerializationSurrogate to strip out the events:
Pros: Dunno
Cons: Pretty complicated to do because the Binary Formatter and Soap
Formatter don't allow you to specify surrogates, so you end up re-writing
them too.

3) Implement ISerializable in a base class and use reflection to get all
private fields in derived classes
Pros: It works
Cons: It's a hack

4) Implement the events in a C# Base class
Pros: You can specify the [NonSerialized] attribute to the event
Cons: Your logic is spread across two projects and two languages.


As you can see. I'm mighty fed up with events. I realize that the fact that
the <NonSerialized> attribute can't be applied to events is probably an
oversight and will probably be fixed in the next version. Saying that, can
anybody think of a valid reason why you would want to serialize an event
(and all objects that handle its events) anyway?


Thanks for putting up with this monkey-ramble. I'm off to learn C# ;)

Cheers,

Trev.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top