4

I have a requirement where I have to serialize the following type hierarchy into YAML

var Variable1 = new
{
    Name = "Variable1",
    Type = typeof(Int32),
    OverWrite = true,
    Value = 10
};
var Variable2 = new
{
    Name = "Variable1",
    Type = typeof(Int32),
    OverWrite = true,
    Value = 10
};

var Job = new
{
    Name = "Job1",
    JobID = 1,
    JobState = "Draft",
    JobStatus = false,
    Parameters = new[]
    {
        Variable1,
        Variable2
    },
    LocalVariables = new[]
    {
        Variable1
    }
};

Here I am getting an exception as

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: Exception has been thrown by the target of an invocation.{"Method may only be called on a Type for which Type.IsGenericParameter is true."}

Please help !!

kometen
  • 6,536
  • 6
  • 41
  • 51
starklord
  • 291
  • 2
  • 6
  • 16
  • When I commented the line [ Type = typeof(Int32), ] in the Variable section , It was successfully serialized – starklord Nov 23 '16 at 10:41

1 Answers1

1

This is because you are trying to serialize a System.Type. That type has lots of properties and some of them throw the exception that you are seeing. This was discussed on issue #212, although in that case the fix was to completely avoid serializing the System.Type.

Ideally, you would be able to register a custom type converter to handle System.Type and serialize it as a string, but due to a shortcoming with the way the object graph is traversed, the property will still be accessed.

Your best solution is probably to wrap the System.Type inside a custom class that serializes as you want:

public struct SerializableType : IYamlConvertible
{
    private Type type;

    void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer)
    {
        var typeName = (string)nestedObjectDeserializer(typeof(string));
        type = typeName != null ? Type.GetType(typeName) : null;
    }

    void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer)
    {
        nestedObjectSerializer(type != null ? type.AssemblyQualifiedName : null);
    }

    public static implicit operator Type(SerializableType value)
    {
        return value.type;
    }

    public static implicit operator SerializableType(Type value)
    {
        return new SerializableType { type = value };
    }
}

Edit

The issue mentioned has been fixed. If you try the latest pre-release package, you will be able to achieve what you want by registering a custom IYamlTypeConverter:

public class SystemTypeTypeConverter : IYamlTypeConverter
{
    public bool Accepts(Type type)
    {
        return typeof(Type).IsAssignableFrom(type);
    }

    public object ReadYaml(IParser parser, Type type)
    {
        var scalar = parser.Expect<Scalar>();
        return Type.GetType(scalar.Value);
    }

    public void WriteYaml(IEmitter emitter, object value, Type type)
    {
        var typeName = ((Type)value).AssemblyQualifiedName;
        emitter.Emit(new Scalar(typeName));
    }
}

// ....

var serializer = new SerializerBuilder()
    .WithTypeConverter(new SystemTypeTypeConverter())
    .Build();

var yaml = serializer.Serialize(new TypeContainer
{
    Type = typeof(string),
});

var deserializer = new DeserializerBuilder()
    .WithTypeConverter(new SystemTypeTypeConverter())
    .Build();

var result = deserializer.Deserialize<TypeContainer>(yaml);

Assert.Equal(typeof(string), result.Type);
Antoine Aubry
  • 12,203
  • 10
  • 45
  • 74
  • Hi, is there any way to serialize the complex types in C# such as DataTable into YAML ? Since I am very beginner with YAML, can you please explain the basics ?? Thanks – starklord Nov 24 '16 at 11:03
  • Basically, the technique is the same. You register a custom `IYamlTypeConverter` that handles the serialization and deserialization. But it would be better if you asked a new question for that, so that I can answer properly. – Antoine Aubry Nov 24 '16 at 14:35