Solved

Why does Dictionary<string, object> not serialize?

Posted on 2010-11-17
21
5,236 Views
Last Modified: 2012-05-10
I have the following classes:

[DataContract]
public class BaseField
{
  private string fieldName;
  private object fieldValue;

  public BaseField(string field, object value)
  {
    fieldName = field;
    fieldValue = value;
  }

  [DataMember]
  public string Name
  {
    get { return fieldName; }
    set { fieldName = value; }
  }

  [DataMember]
  public object Value
  {
    get { return fieldValue; }
    set { fieldValue = value; }
  }

  public string AsString
  {
    get
    {
      return Value.ToString();
    }
  }

  public int AsInteger
  {
      get
      {
        //if we cannot parse, return 0...
        int integer;
        if (!int.TryParse(AsString, out integer))
        {
          integer = 0;
        }
        return integer;
      }
    }
  }
}

[DataContract]
public class FieldCollection
{
  [DataMember]
  private Dictionary<string, BaseField> fieldCollection;
}

[DataContract]
public class TestCollection
{
  [DataMember]
  private Dictionary<string, object> fieldCollection;
}

[DataContract]
public class MyObject : FieldCollection
{
}

When deriving MyObject from FieldCollection I have issues with serialization (the pipe is closed).

When deriving MyObject from TestCollection I have 0 issues. Why can I not serialize FieldCollection? I know it is because I used BaseField in the Dictionary object, but BaseField serializes just fine otherwise. Why is the Dictionary with BaseField not be serializable? How do I get it to serialize?

Also, if try to put a BaseField into my TestCollection dictionary it has issues with the serialization.
0
Comment
Question by:hmstechsupport
  • 11
  • 6
  • 3
  • +1
21 Comments
 
LVL 3

Expert Comment

by:kraiven
Comment Utility
Works fine for me. I take all your classes above are marked serializable? How are you serializing?
0
 

Author Comment

by:hmstechsupport
Comment Utility
[DataContract] is what marks it as serializable
0
 

Author Comment

by:hmstechsupport
Comment Utility
kraiven, these classes compile no problem; so unless you test through a WCF pipe you won't be able to see the behavior I'm talking about.
0
 

Author Comment

by:hmstechsupport
Comment Utility
Just to be sure I added "Serialization" to my BaseField:

[DataContract, Serialization]
public class BaseField

Made no difference.
0
 
LVL 3

Expert Comment

by:kraiven
Comment Utility
Aah! Sorry I didn't realize you were talking about WCF objects. I'm afraid I'm not familiar with them.
0
 
LVL 18

Expert Comment

by:Richard Lee
Comment Utility
Simple, dictionaries are not serializable. You will need to return a List<KeyValuePair<string, BaseField>> instead of a Dictionary<string, BaseField>.

You can easily convert a dictionary to and from a list. see below:

Dictionary to list: myDictionary.ToList();
List to Dictionary: myList.ToDictionary(x => x.Key, y => y.Value);

Remember you are converting to and from a list of KeyValuePairs (List<KeyValuePair<string, BaseField>>).

DaTribe
0
 
LVL 13

Expert Comment

by:Naman Goel
Comment Utility
Hi,
you can create your own dictionary by deriving it from following class XmlDictionary and use it inplace of dictionary this will be serializable easily.

also you can refer to following link for one more method:

http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx
[CollectionDataContract(Name="MyDictionary", ItemName="MyDictionaryItem")]
public class XmlDictionary<TKey, TValue>
{
    /// <summary>
    /// Key/value pair.
    /// </summary>
    public struct DictionaryItem
    {
        /// <summary>
        /// Dictionary item key.
        /// </summary>
        public TKey Key;

        /// <summary>
        /// Dictionary item value.
        /// </summary>
        public TValue Value;
    }

    /// <summary>
    /// Dictionary items.
    /// </summary>
    public DictionaryItem[] Items
    {
        get {
            List<DictionaryItem> items = new List<DictionaryItem>(ItemsDictionary.Count);

            foreach (KeyValuePair<TKey, TValue> pair in ItemsDictionary) {
                DictionaryItem item;

                item.Key = pair.Key;
                item.Value = pair.Value;

                items.Add(item);
            }

            return (items.ToArray());
        }
        set {
            ItemsDictionary = new Dictionary<TKey,TValue>();

            foreach (DictionaryItem item in value)
                ItemsDictionary.Add(item.Key, item.Value);
        }
    }

    /// <summary>
    /// Indexer base on dictionary key.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public TValue this[TKey key]
    {
        get {
            return (ItemsDictionary[key]);
        }
        set {
            Debug.Assert(value != null);
            ItemsDictionary[key] = value;
        }
    }

    /// <summary>
    /// Delegate for get key from a dictionary value.
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public delegate TKey GetItemKeyDelegate(TValue value);

    /// <summary>
    /// Add a range of values automatically determining the associated keys.
    /// </summary>
    /// <param name="values"></param>
    /// <param name="keygen"></param>
    public void AddRange(IEnumerable<TValue> values, GetItemKeyDelegate keygen)
    {
        foreach (TValue v in values)
            ItemsDictionary.Add(keygen(v), v);
    }

    /// <summary>
    /// Items dictionary.
    /// </summary>
    [XmlIgnore]
    public Dictionary<TKey, TValue> ItemsDictionary = new Dictionary<TKey,TValue>();
}

Open in new window

0
 

Author Comment

by:hmstechsupport
Comment Utility
Dictionaries ARE serializable. If I choose to use something like Dictionary<string, string> I even no problems serializing that. Even Dictionary<string, object> serializes, except when I try to put BaseField as the object.

That being said, I'm going to try converting to list and back and see what happens.
0
 

Author Comment

by:hmstechsupport
Comment Utility
Apparently there is no such thing as Dictionary.ToList()
0
 
LVL 13

Expert Comment

by:Naman Goel
Comment Utility
The custom class XmlDictionary<TKey, TValue> is also doing the same.. so you can try that.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 3

Expert Comment

by:kraiven
Comment Utility
hmstechsupport:

There is a ToList() method on Dictionary.
0
 

Author Comment

by:hmstechsupport
Comment Utility
No ToList() for me using .NET 3.5 VS2008
0
 
LVL 3

Expert Comment

by:kraiven
Comment Utility
Well I think ToList is part of the Linq enhancements which are available for .Net 3+.
0
 

Author Comment

by:hmstechsupport
Comment Utility
Not using Linq at all.
0
 
LVL 3

Expert Comment

by:kraiven
Comment Utility
You don't need to explicitly, but if you add a "using System.Linq" statement to your code you will get the Dictionary.ToList() extension method.
0
 
LVL 13

Expert Comment

by:Naman Goel
Comment Utility
Yes ToList method is introduced with :

Version Information
.NET Framework
Supported in: 4, 3.5
.NET Framework Client Profile
Supported in: 4, 3.5 SP1

as part of Linq.

http://msdn.microsoft.com/en-us/library/bb342261.aspx

you can just convert item to list by iterating through each item of dictionary and storing value in list.
0
 
LVL 3

Expert Comment

by:kraiven
Comment Utility
Although dict.ToList() has got to be an improvement on that. ;-)
0
 

Author Comment

by:hmstechsupport
Comment Utility
Using a List<KeyValuePair<string, BaseField>> and converting to a dictionary when I need it also does not work. It seems trying to use BaseField in ANY collection whether it is List, Dictionary, KeyValuePair, will not serialize. I guess this is just not a viable solution. Thanks Microsoft!
0
 

Author Comment

by:hmstechsupport
Comment Utility
I think I finally figured out what was causing the problem and it's simply amazing. Let's take a look at my BaseField constructor:

public BaseField(string field, object value)
{
    fieldName = field;
    fieldValue = value;
}

We pass "object value" when creating a BaseField. Let me give an example of this:

DataTable table = LoadRecordFromDataBase();

DataRow row = table.Rows[0];

Dictionary<string, BaseField> fieldCollection = new Dictionary<string, BaseField>();
foreach (DataColumn column in table.Columns)
{
    BaseField theField = new BaseField(column.ColumnName, row[column.ColumnName]);

    fieldCollection.Add(column.ColumnName, theField);
}


This is a very simple example of how my field collection would be created. Notice how we pass row[column.ColumnName] as the object when creating the BaseField. It turns out if the value of row[column.ColumnName] is BDNull, this causes the collection to fail during serialization.

To avoid the serialization issue I have to pass row[column.ColumnName].ToString() when creating the BaseField. Simply amazing!
0
 

Accepted Solution

by:
hmstechsupport earned 0 total points
Comment Utility
Another solution would be to mark DBNull as a KnownType:

    [DataContract]
    [KnownType(typeof(System.DBNull))]
    public class Field
    {
    }

This also corrects my serialization issues.
0
 

Author Closing Comment

by:hmstechsupport
Comment Utility
Thanks to all who posted.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now