Monday 11 June 2012

.NET 3.5 to .NET 4.0 Enum Serialization/Deserialization (EnumEqualityComparer)

Hi,

I came across an interesting issue and wanted to share it. We had a scenario where a deserialization using BinaryFormatter from .net 4.0 to  .net 3.5 (CLR2.0) raise an exception which contains the following classes:

EnumEqualityComparer,
InvalidCastException,

And the following error messages as well:

"Object Must Implement IConvertible"

"Cannot load type 'System.Collections.Generic.EumEqualityComparer`1...'


I found a solution for this and I would like to explain it with an example:

Suppose you have an enum:

enum TileSize
{
         Big = 1,
         Medium = 2,
         Small = 3
}

and you have a code where you are using a dictionary:

IDictionary<TileSize, int> items = new Dictionary<TileSize, int>();

items.Add(TileSize.Big, 20); //we have 20 tiles of size big.
items.Add(TileSize.Small, 10); //we have 10 tiles of size small.


Now, if you have a client/server environment where you have got .net 4.0 server and a .net 3.5 (CLR 2.0) client.

when you will try to serialize this items object using BinaryFormatter, it will serialize perfectly fine but on deserialization on the client side you will encounter error explaining "Object Must Implement IConvertible" and also you will see  the following error on client:

"Cannot load type 'System.Collections.Generic.EumEqualityComparer`1...'

Why I get this error?


The class EnumEqualityComparer is internally used in .NET 4.0 and it is new to CLR2.0.

When the class TileSize is serialized, The BinaryFormatter in .NET 4.0 uses EnumEqualityComparer to serialize and deserialize an Enum whereas the earlier frameworks use System.Collection.Generic.ObjectEqualityComparer.

How to fix?

An easiest way to fix this issue is to place a base type other than integer, for an enum, like the following:


enum TileSize : byte
{
         Big = 1,
         Medium = 2,
         Small = 3
}


When we put an 'non int' base type for an enum, the BinaryFormatter of .NET 4.0 uses ObjectEqualityComparer instead of EnumEqualityComparer. And the object easily gets deserialized on lower version of .NET Framework.


I think the article is very simple and helpful. Still if you have any question, please feel free to comment.

Regards
Kajal



6 comments:

  1. Cool solution! You had prevent me from wasting time trying to find out the solution.

    ReplyDelete
  2. You saved us from going insane trying to figure this out. Thanks!

    ReplyDelete
  3. Thank you so much for this simple solution!

    ReplyDelete
  4. I'm having the same issue, except our customers are using our application compiled against 4.5 .NET framework. Recently someone installed Windows 10 which uses .NET 4.6. During deserialization, I get the same exception you listed in your example; "Cannot load type 'System.Collections.Generic.EumEqualityComparer`1. " I tried adding the 'byte' to my int enum, but it didn't seem to make a difference.
    Ironically, .NET 4.4 and 4.6 both use the EumEqualityComparer during serialization. I can't figure out what I need to change so our customers can open their project files in Windows 10.

    any other ideas will be appreciated.

    thank you

    ReplyDelete
  5. Also, please contact me via email if you have any ideas...
    gcadmes@gmail.com

    thanks

    ReplyDelete