Solved

Why does Dictionary<string, object> not serialize?

Posted on 2010-11-17
21
5,550 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 6
  • 3
  • +1
21 Comments
 
LVL 3

Expert Comment

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

Author Comment

by:hmstechsupport
ID: 34156282
[DataContract] is what marks it as serializable
0
 

Author Comment

by:hmstechsupport
ID: 34156302
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
Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

 

Author Comment

by:hmstechsupport
ID: 34156364
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
ID: 34156394
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
ID: 34156574
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
ID: 34156751
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
ID: 34156766
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
ID: 34156777
Apparently there is no such thing as Dictionary.ToList()
0
 
LVL 13

Expert Comment

by:Naman Goel
ID: 34156778
The custom class XmlDictionary<TKey, TValue> is also doing the same.. so you can try that.
0
 
LVL 3

Expert Comment

by:kraiven
ID: 34156820
hmstechsupport:

There is a ToList() method on Dictionary.
0
 

Author Comment

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

Expert Comment

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

Author Comment

by:hmstechsupport
ID: 34156947
Not using Linq at all.
0
 
LVL 3

Expert Comment

by:kraiven
ID: 34157012
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
ID: 34157029
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
ID: 34157075
Although dict.ToList() has got to be an improvement on that. ;-)
0
 

Author Comment

by:hmstechsupport
ID: 34157262
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
ID: 34173402
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
ID: 34173782
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
ID: 34203665
Thanks to all who posted.
0

Featured Post

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
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…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…

622 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