C# DataContractSerializer SerializationException with Enum set in object field
Asked Answered
T

3

2

Given the following code,

[DataContract]
public class TestClass
{
  [DataMember]
  public object _TestVariable;

  public TestClass(object value)
  {
    _TestVariable = value;
  }

  public void Save()
  {
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(new FileStream("test.tmp", FileMode.Create)))
    {
      DataContractSerializer ser = new DataContractSerializer(typeof(TestClass));
      ser.WriteObject(writer, this);
    }
  }
}

public enum MyEnum
{
  One,
  Two,
  Three
}

Why does it fail to serialize when _TestVariable is set to an Enum value?

new TestClass(1).Save(); // Works
new TestClass("asdfqwer").Save(); // Works
new TestClass(DateTime.UtcNow).Save(); // Works
new TestClass(MyEnum.One).Save(); // Fails

The exception thrown is:

System.Runtime.Serialization.SerializationException : Type 'xxx.MyEnum' with data contract name 'xxx.MyEnum:http://schemas.datacontract.org/2004/07/Tests' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
Toluol answered 7/4, 2011 at 7:19 Comment(2)
what problem are you trying to solve by using object type for _TestVariable, perhaps you could explain the real problem.Jillene
See the answer to a similar question https://mcmap.net/q/188905/-quot-type-not-expected-quot-using-datacontractserializer-but-it-39-s-just-a-simple-class-no-funny-stuffMastoidectomy
V
6

You should use KnownTypeAttribute on TestClass.

[DataContract]
[KnownTypeAttribute(typeof(MyEnum))]
public class TestClass
Vaishnava answered 7/4, 2011 at 7:25 Comment(2)
bingo! this makes it compile, but is a pain. Aren't enums simple types to serialize?Toluol
That's not about enums. That's about using variable of type object instead of exact type. In this case, serializer has no knowledge about what type it will encounter during serialization and deserialization, so you should make it know via this attribute. If you used exact data type and not object, this whould not be neededVaishnava
B
4

Another option that you could employ to avoid having to put the KnownType attribute all over the place is to use type deduction to do the work for you.

class Program
{
    static void Main(string[] args)
    {
        TestClass.Create(1).Save(); // Works
        TestClass.Create("asdfqwer").Save(); // Works
        TestClass.Create(DateTime.UtcNow).Save(); // Works
        TestClass.Create(MyEnum.One).Save(); // Fails
    }
}

public class TestClass
{
    public static TestClass<T> Create<T>(T value)
    {
        return new TestClass<T>(value);
    }
}

[DataContract]
public class TestClass<T>
{
    [DataMember]
    public T _TestVariable;

    public TestClass(T value)
    {
        _TestVariable = value;
    }

    public void Save()
    {
        using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(new MemoryStream()))
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(TestClass<T>));
            ser.WriteObject(writer, this);
        }
    }
}

public enum MyEnum
{
    One,
    Two,
    Three
}
Barela answered 8/12, 2012 at 20:20 Comment(0)
Z
0

MyEnum is not marked as serializable. Adding DataContractAttribute to MyEnum should fix it.

Zimmermann answered 7/4, 2011 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.