asynkron / Wire

Binary serializer for POCO objects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to deserialize anonymous object

nowol opened this issue · comments

commented

Hi,

I was wondering if this was a supported case:

  • On computer 1: serialize anonymous object
  • Send the serialized bytes to another computer (using a file, Redis, database, etc)
  • On computer 2: deserialize the serialized bytes

I get the following error while deserializing:

Additional information: Could not load type '<>f__AnonymousType0`2' from assembly XYZ

The message make sense since the anonymous type was never created on computer 2.

On an unrelated note: for run I plugged in Wire in my own binary serializer unit tests and I was wondering if you would like to know the issues I found.

commented

I didn't find a list of what was supported/unsupported by Wire so the following issues may be 'by design'.

All tests uses the following method:

    public override T Duplicate<T>(T obj)
    {
        using (var ms = new MemoryStream())
        {
            SerializerOptions opt = new SerializerOptions(preserveObjectReferences: true);
            var s = new Wire.Serializer(opt);
            s.Serialize(obj, ms);
            ms.Position = 0;
            return s.Deserialize<T>(ms);
        }
    }

1 - Serializing a list of IQueryable results in an "Ambiguous match found" exception:

    var list = new List<int> { 123, 123, 123 };
    List<IQueryable<int>> instance = new List<IQueryable<int>> { list.AsQueryable() };

    var duplicatedValue = Duplicate(instance);

2 - Fields marked with [NonSerialized] should not be serialized.

3 - I have a bunch of tests that uses custom dictionaries that throws "Generic IDictionary<TKey,TValue> are not yet supported" but I guess this is expected for now.

4 - Serializing/Deserializing a Dictionary<byte, char> does not deserialize the values.

    var instance = new Dictionary<byte, char>();
    instance.Add(0, 'z');
    instance.Add(255, 'z');
    instance.Add(3, char.MinValue);
    var duplicatedValue = Duplicate(instance);
    Assert.AreEqual(instance.Count, duplicatedValue.Count);
    CollectionAssert.AreEquivalent(instance.Keys, duplicatedValue.Keys);
    foreach (var kvp in instance)
    {
        Assert.AreEqual(kvp.Value, duplicatedValue[kvp.Key]);
    }

5 - Dictionary/HashTable comparer are not serialized.

    var instance = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase)
    {
        {"a", 123},
        {"", "abc"}
    };

    var duplicatedValue = Duplicate(instance);
    Assert.AreEqual(instance.Comparer.GetType(), duplicatedValue.Comparer.GetType());

6 - Serializing/Deserializing an ExpandoObject results in the following exceptions:

threw exception System.NullReferenceException, but exception System.NotSupportedException was expected. Exception message: System.NullReferenceException: Object reference not set to an instance of an object.
    dynamic instance = new ExpandoObject();
    instance.Property1 = 123;
    Duplicate(instance);

7 - Serializing/Deserializing a HashTable throws this exception:

threw exception System.Reflection.TargetParameterCountException, but exception System.NotSupportedException was expected. Exception message: System.Reflection.TargetParameterCountException: Parameter count mismatch.
    var instance = new Hashtable { {1, 2}, {"a", "b"}, };
    var duplicatedValue = Duplicate(instance);

8 - Serializing/Deserializing a multidimentional array:

threw exception System.ArgumentException, but exception System.NotSupportedException was expected. Exception message: System.ArgumentException: Value was invalid.
    var instance = new int[1,2,3,4,5];
    var duplicatedValue = Duplicate(instance);
    instance.Should().BeEquivalentTo(duplicatedValue);

9 - Serializing a null array is not supported but this looks like a design decision.

    object[] instance = null;
    var duplicatedValue = Duplicate(instance);

10 - Serializing a pointer throws this exception:

threw exception System.Security.VerificationException, but exception System.NotSupportedException was expected. Exception message: System.Security.VerificationException: Operation could destabilize the runtime.
    int[] a = new int[5] { 10, 20, 30, 40, 50 };
    fixed (int* p = &a[0])
    {
        var instance = new ClassWithPointer();
        instance.Value = p;
        Duplicate(instance);
    }

    public unsafe class ClassWithPointer
    {
        public int* Value { get; set; }
    }

11 - Serializing an Expression throws exception:

threw exception System.Reflection.AmbiguousMatchException, but exception System.NotSupportedException was expected. Exception message: System.Reflection.AmbiguousMatchException: Ambiguous match found.
    var testData = new List<int> { 1, 2, 3, 4, 5, 6 };
    Expression<System.Func<int, bool>> instance = x => x > 3;
    var duplicatedValue = Duplicate(instance);

12 - Serializing a delegate/Func<>/Action<> should not be allowed because the types will not exists in another computer.

  1. Not planned, an IQueryable could be just anything, an EF query or whatever, they are highly context bound. we will not support anything that magic out of the box.
  2. This should be the case as we filter out those fields, are you seeing a different behavior?
  3. Planned, not implemented.
  4. Bug, it works with string values, so something wrong with Char values ATM.
  5. Not implemented, it should probably be possible to just serialize the comparer. need to research this one a bit.
  6. Not planned, PR would be accepted though.
  7. Bug
  8. Planned, not implemented.
  9. serializing null as the root object is not supported. it could be, but I don't think it makes sense.
  10. Not planned. I dont see how this could be useful as the pointer would be useless when deserialized.
    Would it make more sense to just ignore it?
  11. Planned, not implemented.
  12. works if both systems reference the same assembly.

And TBH. all of these should be reported as individual issues

commented

2 - The field with the [NonSerialized] was serialized

5 - You could support the ISerializable interface for this.

6 - I have my own serializer to take care of so I will not be able to do a PR. However if you decide to support it you can treat ExpandoObject as a Dictionary<string, object>

10 - I think it would be best if you can throw your own exception with more detail (e.g.: pointer is not supported for Type X, field Y) it would help the user consuming your library instead of letting the framework handle it.

I was just wondering how well Wire worked. I'll close this issue and let you open issues for what you want to fix.