-
Jun 27th, 2011, 09:18 PM
#1
[.NET 2.0] Is Type/Structure Serializable
I had a recent need for checking if a structure, and all the members inside of it, were serializable to avoid throwing a serialization exception on certain systems -where throwing one would be very costly, and in a situation where I might not know exactly what's being passed through the stream and attempting to be serialized.
So after loads of google searching, I only found various ideas on how to do such a thing, mostly checking the single instance or the main structure itself. I can mark that as serializable, but what if one of the types inside isn't? Say, for some reason, the structure contains a TcpClient, or a MemoryStream. Neither of those is technically serializable and would throw an exception when attempting to be serialized.
Finally, after a bit of experimenting in Visual Studio and with plenty of help from IntelliSense, I found a way to finally do it!
Code:
''' <summary>
''' Determines if a structure is serializable.
''' </summary>
''' <typeparam name="T">The structure to test.</typeparam>
''' <returns>A boolean indicating if the structure can be serialized.</returns>
''' <remarks>It's really simple to check. If your structure is Foo, then you simply call the function as so:
''' IsStructureSerializable(Of Foo), and you will get a boolean value.</remarks>
Public Function IsStructureSerializable(Of T As Structure)() As Boolean
'Just a wrapper around the IsTypeSerializable.
Return IsTypeSerializable(GetType(T))
End Function
''' <summary>
''' Determines if a class is serializable.
''' </summary>
''' <typeparam name="T">The class to test.</typeparam>
''' <returns>A boolean indicating if the class can be serialized.</returns>
''' <remarks>It's pretty simple to check. If your class is called Foo, then you simply call the function as so:
''' IsClassSerializable(Of Foo), and you will get a boolean value.</remarks>
Public Function IsClassSerializable(Of T As Class)() As Boolean
'Just a wrapper around the IsTypeSerializable.
Return IsTypeSerializable(GetType(T))
End Function
''' <summary>
''' Loops through the entire object to see if it is indeed serializable.
''' </summary>
''' <param name="type">The object Type to check.</param>
''' <returns>A boolean that indicates if the object passed is able to be successfully serialized.</returns>
''' <remarks>This function is recursive and will ignore any fields marked as "NonSerialized".
''' However, if at any time there is a field that cannot be serialized, and it is not marked as "NonSerialized", the routine will end and immediately return false.</remarks>
Public Function IsTypeSerializable(ByVal type As [Type]) As Boolean
'Final serializable result
Dim _result As Boolean = True
'Make sure our current type is serializable
If type.IsSerializable Then
'Ok, so now get any sub-fields.
Dim _subFields() As Reflection.FieldInfo = type.GetFields(Reflection.BindingFlags.Instance Or
Reflection.BindingFlags.DeclaredOnly Or
Reflection.BindingFlags.Public Or
Reflection.BindingFlags.NonPublic)
'Loop each subfield
For Each _field As Reflection.FieldInfo In _subFields
'Get the type
Dim _type As Type = _field.FieldType
'See some details about this.
Console.WriteLine("-------------------------------")
Console.WriteLine(String.Format("Checking Type: {0}", _type.ToString()))
Console.WriteLine("Name: {0}", _field.Name)
Console.WriteLine("Private: {0}", _field.IsPrivate)
Console.WriteLine("Public: {0}", _field.IsPublic)
Console.WriteLine("Static: {0}", _field.IsStatic)
Console.WriteLine("Primitive: {0}", _type.IsPrimitive)
'Get an object array to see if this type is marked as NonSerialized.
Dim _attribues() As Object = _field.GetCustomAttributes(GetType(NonSerializedAttribute), False)
'Check
If _attribues IsNot Nothing AndAlso _attribues.Length > 0 Then
'This is to be ignored!
Console.WriteLine("Type {0} is marked for NonSerializable!", _field.ToString)
Else
'Check if it's a primitive
If _type.IsPrimitive Then
'It is.
_result = True
Else
'We have to go deeper.
_result = IsTypeSerializable(_type)
End If
End If
'Write out the result
Console.WriteLine("Type {0} {1} serializable", _type.ToString(), If(_result AndAlso _attribues.Length.Equals(0), "is", "is not"))
Console.WriteLine("-------------------------------")
Console.WriteLine()
'Check
If Not _result Then Exit For
Next
Else
'The structure is not serializable
_result = False
End If
'Give back the result
Return _result
End Function
It takes the "Type" of the structure, so, you would pass it like so:
Code:
Public Structure XYZ
End Structure
Console.WriteLine(IsStructureSerializable(Of XYZ))
Console.WriteLine(IsTypeSerializable(GetType(XYZ))
The code will retrieve Private, Public, Static or Protected variables in a class or structure and, as far as I know, should always work. If there are any problems, please let me know!
EDIT: Updated with a suggestion from Nick (who was gracious enough to provide an example on how to do it! Thanks Nick!)
EDIT 2: Another update with overloads (suggested by Nick awhile back...I just got lazy).
Last edited by formlesstree4; Jul 8th, 2011 at 11:02 AM.
Reason: Updated code and included two additional routines.
-
Jun 28th, 2011, 08:38 AM
#2
Re: [.NET 2.0] Is Type/Structure Serializable
What about properties? I'm not absolutely sure but doesn't GetFields return fields only, eg not properties? Yes, properties usually have backing fields so that should work, but what if you use the new VS2010 auto properties? They don't have backing fields in the source code, but they might be generated behind the scenes, I don't know... Either way it seems strange to just check fields.
-
Jun 28th, 2011, 09:33 AM
#3
Re: [.NET 2.0] Is Type/Structure Serializable
It makes sense... structures only have fields... that's one of the differences between types and classes... there's more, but that's probably the main difference. Now, if you want to expand it to include Types/Structures And classes, then yes, you would need to check Fields and Properties - backing fields would be private, excluded (or should be) from the GetFields (which makes sense since a private variable wouldn't be a field), and would be serializable by nature in the first place.
-tg
-
Jun 28th, 2011, 10:16 AM
#4
Re: [.NET 2.0] Is Type/Structure Serializable
I could have swarn I read 'class' a few times in there too. Can't find it anymore; either it's been edited out or I'm going crazy But yeah if it's only for structures then it should work. As for private fields not being fields, aren't they? He is explicitly checking for non-public fields as well, I would assume that includes private fields?
-
Jun 28th, 2011, 10:20 AM
#5
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by formlesstree4
The code will retrieve Private, Public, Static or Protected variables in a class or structure and, as far as I know, should always work. If there are any problems, please let me know!
Ah, there is it, I knew I wasn't crazy I guess what he says here is correct (assuming it does indeed get private fields as well as I would think) but if you passed a class it wouldn't check the properties.
Can you check whether a type is a class or structure? I'm sure you can get that info somewhere in the Type object.
You could also add a generic overload to save a couple of characters of typing
Code:
Public Function IsTypeSerializable(Of T As Structure)() As Boolean
Dim type As Type = GetType(T)
Return IsTypeSerializable(type)
End Function
Code:
If IsTypeSerializable(Of SomeStructure)() Then ...
You should only be able to pass structures to this generic overload.
-
Jun 28th, 2011, 10:58 AM
#6
Re: [.NET 2.0] Is Type/Structure Serializable
I'd also think it wouldn't be worth checking private fields... as they aren't going to be serialized -- which reminds me... Read-Only properties don't serialize very well at all. Correction, they serialize quite well... they just don't deserialize. Meanwhile the converse is true about Write-Only properties. So that might be something to make sure you take a look at.
-tg
-
Jun 28th, 2011, 11:11 AM
#7
Re: [.NET 2.0] Is Type/Structure Serializable
Hm, I didn't know private fields don't serialize. I've never done much serialization and the few things I did do was more trial and error than anything else... I can imagine many scenarios where vital information is stored in private fields, so if those aren't serialized how will you get your original object back after deserializing? Or is that simply something to keep in mind, that you won't get private fields back?
As for read-only properties, I don't see why they should serialize. Most of the time they return a value calculated 'on-the-fly' (from other properties for example) (no need to serialize those values) or return a private field. If private fields are serialized, then the read-only properties don't need to be because the value is already serialized from the private field. On the other hand, if private fields aren't serialized, then the property is going to lose its value anyway so again there's no need to serialize it...?
-
Jun 28th, 2011, 01:01 PM
#8
Re: [.NET 2.0] Is Type/Structure Serializable
serialization sucks out anything that's readable... which is why read-only properties serliaize.... unless you explicitly mark it as serialize ignore. I've had to do that on a couple of occasions... which is also how I happen to know that private member variables do no serialize. Serialization is a PUBLIC representation of the data that's in the class. And in the specific case I'm thinking of the read only property was a collection of other classes ... in keeping with the overall structure of how objects and list of objects are in the framework, the List(Of T) was read only... the items IN the list are read/write... not that different from data rows in a datatable ... the datarows collection is read-only which means you simply cannot assign the DataRows form one datatable to the DataRows of another directly... and for good reason. In the end we had no choice but to expose our list as a get/set property just so we could deserialize it. Man, that had been a long week.
"I can imagine many scenarios where vital information is stored in private fields, so if those aren't serialized how will you get your original object back after deserializing? Or is that simply something to keep in mind, that you won't get private fields back?"
You either keep that in mind, and decide it's not all that vital after all... or you expose a public property that can be serialized for those values. Or you write a property where the read (get) combines all of the values into a single string of some kind and the write (set) takes a formatted string and breaks it up into it's individual components. Ugly, but it's known to work.
-tg
-
Jun 28th, 2011, 01:22 PM
#9
Re: [.NET 2.0] Is Type/Structure Serializable
Wow, I had some people respond!
Anyway, I chose to ignore properties for the most part; my requirements for writing this at the time did not necessitate properties to be included because using the GetMembers() actually will find the property anyway.
I tested this theory a few seconds ago by creating a structure with the Property "X" as a string and here's what the code output:
It still found the required variable and checked it. Apparently the compiler simply put a "_" in front of the variable name at compile-time (This was done using VS2010 as one can do single-line properties). To be a bit more thorough, I tested Read-Only properties and found that they were ignored which, to me, indicates that perhaps the serializer would also ignore them since, being read-only, would not need to be reloaded anyway.
The same held true for Write-Only Properties; they were ignored.
EDIT: Marking a field as "NotSerialized" doesn't change whether or not it is read by this routine. Just thought I'd throw that in there.
Last edited by formlesstree4; Jun 28th, 2011 at 01:27 PM.
Reason: Small update!
-
Jun 28th, 2011, 01:37 PM
#10
Re: [.NET 2.0] Is Type/Structure Serializable
That makes sense. It's still not retrieving properties, it's just that the compiler creates a private backing field (_X) behind the scenes, and that's the field you're getting. I guess that's ok then since I cannot think of any other kind of property (eg, one that does not return a private backing field) which should be serialized.
As for 'NotSerializable', shouldn't you ignore those fields in your code? If I provide a type that has a property that is not serializable, and I know that so I mark it with NotSerializable (or Serializable(false) or however it goes) then your code should tell me I can serialize my structure, no?
-
Jun 28th, 2011, 01:38 PM
#11
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by NickThissen
That makes sense. It's still not retrieving properties, it's just that the compiler creates a private backing field (_X) behind the scenes, and that's the field you're getting. I guess that's ok then since I cannot think of any other kind of property (eg, one that does not return a private backing field) which should be serialized.
As for 'NotSerializable', shouldn't you ignore those fields in your code? If I provide a type that has a property that is not serializable, and I know that so I mark it with NotSerializable (or Serializable(false) or however it goes) then your code should tell me I can serialize my structure, no?
It should, but I don't know enough yet on how to check if a member is marked as not Serializable. I'll have to do some more experimenting.
-
Jun 28th, 2011, 01:41 PM
#12
Re: [.NET 2.0] Is Type/Structure Serializable
mmmm.... I wonder if this is checking if the type can be serialized... not whether it is serializable in context... because a Read-only property CAN be serialized... that's what led to problems I had a while back when trying to serialize some date to be sent off to BizTalk...
Hmmm.... I see what you're doing is simply checking to see if it is a Primitive Type... and if so, assuming it's serializable... and if not, then you're calling it recursively on the new type...which is why the NotSerialized flag has no bearing on your code... odds are, for your purpose, simply determining if the type is primitive or not (and it also assumes that everything can be broken down into a primitive type... which may not be the case) ... and assume that if it is a primitive, it's serializable. From a generic view... the assumption can't/shouldn't be made.
-tg
-
Jun 28th, 2011, 01:44 PM
#13
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by techgnome
mmmm.... I wonder if this is checking if the type can be serialized... not whether it is serializable in context... because a Read-only property CAN be serialized... that's what led to problems I had a while back when trying to serialize some date to be sent off to BizTalk...
Hmmm.... I see what you're doing is simply checking to see if it is a Primitive Type... and if so, assuming it's serializable... and if not, then you're calling it recursively on the new type...which is why the NotSerialized flag has no bearing on your code... odds are, for your purpose, simply determining if the type is primitive or not (and it also assumes that everything can be broken down into a primitive type... which may not be the case) ... and assume that if it is a primitive, it's serializable. From a generic view... the assumption can't/shouldn't be made.
-tg
I do first check to make sure that the type itself is marked as serializable/can be serialized, and then to see if it's a primitive. If it's not, it keeps going down to find, hopefully, the base elements, as most primitives that I know of can in fact be serialized. If you're willing to point out a few types that aren't serializable, I could plug things in (Or someone can) and hopefully it will work. This was done after only a few hours of research and a lot of playing around; I'm not saying the code is bug-free or that it will always work, it just seems to work for the cases that I bring to it.
-
Jun 28th, 2011, 01:59 PM
#14
Re: [.NET 2.0] Is Type/Structure Serializable
As far as I know the NotSerialized we were talking about are just attributes, right?
You use them like this?
Code:
Public Structure XYZ
Public X As String
Public Y As String
<NonSerialized()> _
Public Z As String
End Structure
If I understand correctly, Z will not be serialized in this case.
You can add this check to your code by simply obtaining the 'custom attributes' for the type of your field, using Type.GetCustomAttributes(Type, Boolean).
Example:
vb.net Code:
Public Class Form1 Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Dim t = GetType(XYZ) For Each f As FieldInfo In t.GetFields(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic) Dim attributes = f.GetCustomAttributes(GetType(NonSerializedAttribute), False) If attributes IsNot Nothing AndAlso attributes.Length > 0 Then ' This field is marked NonSerialized... MessageBox.Show(f.Name) End If Next End Sub End Class <Serializable()> _ Public Structure XYZ Public X As String Public Y As String <NonSerialized()> _ Public Z As String End Structure
Messagebox shows 'Z'.
If the NonSerialized attribute is specified for a 'child field' I think you should return True for that field. My reasoning is simple: if this field happens to be non-serializable than that would tell your code that the entire parent field is not serializble, which it still might be because this child field will not be serialized anyway and the programmer is aware of that.
If the attribute is specified for the parent structure than I guess you should return false, though that's debatable. Technically you could serialize it, it probably just wouldn't do anything.
-
Jun 28th, 2011, 02:18 PM
#15
Re: [.NET 2.0] Is Type/Structure Serializable
Thanks for the suggestion Nick. I've been able to successfully integrate it into the code and will update the main post with it soon. It makes the output a little wonky, but it still works out in the end.
-
Jun 28th, 2011, 02:18 PM
#16
Re: [.NET 2.0] Is Type/Structure Serializable
"I do first check to make sure that the type itself is marked as serializable/can be serialized" -- yeah... that's the TYPE... NOT the property... Even when the type can be serialized, members of the type/class may or may not be... given Nick's code above... if I were to serialize that, I would expect (and would get) X and Y in the resulting serialized data. That's the way it should be...
when I then deserialize, I'd expect X and Y to rehydrate themselves but not Z... That's jsut the way serialization is... you've (or someone) has explicitly stated that Z should not be serialized (may be it's an SSN or a CC#) ... but that X & Y are OK to serialize.
Just because Z isn't serializable, doesn't make XYZ (the structure) non serializable though, since X & Y could still be.
Now... a structure that has all of it's members NotSerializable... might as well just mark the whole structure as NonSerializable.
-tg
-
Jun 28th, 2011, 02:21 PM
#17
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by techgnome
"I do first check to make sure that the type itself is marked as serializable/can be serialized" -- yeah... that's the TYPE... NOT the property... Even when the type can be serialized, members of the type/class may or may not be... given Nick's code above... if I were to serialize that, I would expect (and would get) X and Y in the resulting serialized data. That's the way it should be...
when I then deserialize, I'd expect X and Y to rehydrate themselves but not Z... That's jsut the way serialization is... you've (or someone) has explicitly stated that Z should not be serialized (may be it's an SSN or a CC#) ... but that X & Y are OK to serialize.
Just because Z isn't serializable, doesn't make XYZ (the structure) non serializable though, since X & Y could still be.
Now... a structure that has all of it's members NotSerializable... might as well just mark the whole structure as NonSerializable.
-tg
I just updated the code to check for the NonSerialized() attribute. I ran a few tests and it worked as expected.
-
Jun 28th, 2011, 02:21 PM
#18
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by techgnome
"I do first check to make sure that the type itself is marked as serializable/can be serialized" -- yeah... that's the TYPE... NOT the property... Even when the type can be serialized, members of the type/class may or may not be...
His code is recursive so that check is done for every field as well (and every field of those fields, and every field of the fields of those fields, and... you get it). It does not of course take into account that the writer of the structure might not WANT a field serializable, which is when he would use the NonSerialized attribute.
-
Jun 28th, 2011, 02:26 PM
#19
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by techgnome
Just because Z isn't serializable, doesn't make XYZ (the structure) non serializable though, since X & Y could still be.
As for this, I think you meant 'just because Z isn't supposed to be serialized...', otherwise I don't agree. The point of this function is to check whether a type and all its members are serializable. If one of its members is not serializable then it would return false.
But there's a different between a type not being serializable and a type marked with the NonSerialized attribute; in the first case the function should return false (a field somewhere down the tree of fields of this type is not serializable, so not all members are serializable), but in the second case it should return true (since the field IS serializable, the author just didn't want it to be serialized).
Also, is anyone else copy/pasting 'serializable' each time to avoid having to write that horrible word over and over?
-
Jun 28th, 2011, 02:29 PM
#20
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by NickThissen
As for this, I think you meant 'just because Z isn't supposed to be serialized...', otherwise I don't agree. The point of this function is to check whether a type and all its members are serializable. If one of its members is not serializable then it would return false.
Correct
Originally Posted by NickThissen
But there's a different between a type not being serializable and a type marked with the NonSerialized attribute; in the first case the function should return false (a field somewhere down the tree of fields of this type is not serializable, so not all members are serializable), but in the second case it should return true (since the field IS serializable, the author just didn't want it to be serialized).
And because of this, I have the checking not go deeper because there's no reason to continue looking.
Originally Posted by NickThissen
Also, is anyone else copy/pasting 'serializable' each time to avoid having to write that horrible word over and over?
Surprisingly no, but I keep misspelling the bloody word every now and then.
-
Jun 28th, 2011, 02:59 PM
#21
Re: [.NET 2.0] Is Type/Structure Serializable
Originally Posted by NickThissen
As for this, I think you meant 'just because Z isn't supposed to be serialized...', otherwise I don't agree. The point of this function is to check whether a type and all its members are serializable. If one of its members is not serializable then it would return false.
Which is why I commented that specific to his needs, it was probably fine... but should anyone else try to use it for a more generic application... it's going to need some work...
Originally Posted by NickThissen
But there's a different between a type not being serializable and a type marked with the NonSerialized attribute; in the first case the function should return false (a field somewhere down the tree of fields of this type is not serializable, so not all members are serializable), but in the second case it should return true (since the field IS serializable, the author just didn't want it to be serialized).
Tomaytoe... Tomahtoe... depends on what the end result is... I'm looking at this from a more generic approach... should someone try to reuse the code... but you're right, there's two types... as formless even noted in the opening post... if you try to serialize a stream, it's not going to end well... you're better off crossing the streams instead. But only if you're using the Gozer protocol.
Originally Posted by NickThissen
Also, is anyone else copy/pasting 'serializable' each time to avoid having to write that horrible word over and over?
no, but I need to add it to my browser's library... and deserialization too... ugh blagnog... this post looks like it's been shot at on the streets of LA, there's so much red squigglies.
-tg
-
Jul 8th, 2011, 11:01 AM
#22
Re: [.NET 2.0] Is Type/Structure Serializable
Small update to provide methods for easily calling classes and structures (if one was too lazy to use a GetType())
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|