Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 5738
  • Last Modified:

Why does Dictionary<string, object> not serialize?

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
hmstechsupport
Asked:
hmstechsupport
  • 11
  • 6
  • 3
  • +1
1 Solution
 
kraivenCommented:
Works fine for me. I take all your classes above are marked serializable? How are you serializing?
0
 
hmstechsupportAuthor Commented:
[DataContract] is what marks it as serializable
0
 
hmstechsupportAuthor Commented:
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
hmstechsupportAuthor Commented:
Just to be sure I added "Serialization" to my BaseField:

[DataContract, Serialization]
public class BaseField

Made no difference.
0
 
kraivenCommented:
Aah! Sorry I didn't realize you were talking about WCF objects. I'm afraid I'm not familiar with them.
0
 
Richard LeeSoftware EnthusiastCommented:
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
 
Naman GoelCommented:
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
 
hmstechsupportAuthor Commented:
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
 
hmstechsupportAuthor Commented:
Apparently there is no such thing as Dictionary.ToList()
0
 
Naman GoelCommented:
The custom class XmlDictionary<TKey, TValue> is also doing the same.. so you can try that.
0
 
kraivenCommented:
hmstechsupport:

There is a ToList() method on Dictionary.
0
 
hmstechsupportAuthor Commented:
No ToList() for me using .NET 3.5 VS2008
0
 
kraivenCommented:
Well I think ToList is part of the Linq enhancements which are available for .Net 3+.
0
 
hmstechsupportAuthor Commented:
Not using Linq at all.
0
 
kraivenCommented:
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
 
Naman GoelCommented:
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
 
kraivenCommented:
Although dict.ToList() has got to be an improvement on that. ;-)
0
 
hmstechsupportAuthor Commented:
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
 
hmstechsupportAuthor Commented:
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
 
hmstechsupportAuthor Commented:
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
 
hmstechsupportAuthor Commented:
Thanks to all who posted.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 11
  • 6
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now