Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Deserialization] Scalar or Object #531

Closed
Oleexo opened this issue Sep 18, 2020 · 1 comment
Closed

[Deserialization] Scalar or Object #531

Oleexo opened this issue Sep 18, 2020 · 1 comment

Comments

@Oleexo
Copy link

Oleexo commented Sep 18, 2020

Hi guys,

I try to deserialize somethings like that:

test:
  key1:
     property1: p1
     property2: p2
  key2:
     property1: p1
     property2: p2

So I created a class like this:

public class Root {
  public Dictionnary<string, MyCustomObject> Test { get; set; }
}

public class MyCustomObject {
   public string Property1 { get; set; }
   public string Property2 { get; set; }
}

until here everythings is ok BUT ! The yaml can also be written like that:

test:
  key1: p1
  key2:
     property1: p1
     property2: p2

In this case, the instance of MyCustomObject with the key 'key1' have for values: Property1 = p1 and Property2 = Some default value.
I have a very long yaml file with many situation like this. I can't find an option for intercept this case and create a little pieces of code to handle the case:
=> IsScalar so the scalar property goes here in the object
=> IsObject so deserialize with the default class and configuration

If you have have any clue how I can create a behavior like that without recreating the property mapper ?

Thanks !

@EdwardCooke
Copy link
Collaborator

I know this is old, but here's a potential answer, you can create a YamlTypeConverter class that takes the tokens from the YAML stream and parses them in to an object. If the token is a scalar, set your single property and return the object, else if it is a mappingstart, read through them in an alternating key/value pair of scalars. It's not the cleanest solution, but it might work for what you are looking to do.

An example of such a converter is this:

using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;

public class MyCustomObjectTypeConverter : IYamlTypeConverter
{
    public bool Accepts(Type type)
    {
        return type == typeof(MyCustomObject);
    }

    public object? ReadYaml(IParser parser, Type type)
    {
        if (parser.TryConsume<Scalar>(out var scalar))
        {
            var result = new MyCustomObject
            {
                Property1 = scalar.Value
            };
            return result;
        }
        else if (parser.TryConsume<MappingStart>(out var _))
        {
            var result = new MyCustomObject();
            while (!(parser.Current is MappingEnd))
            {
                //key
                var key = parser.Consume<Scalar>();
                var value = parser.Consume<Scalar>();
                switch (key.Value.ToLowerInvariant())
                {
                    case "property1":
                        result.Property1 = value.Value;
                        break;
                    case "property2":
                        result.Property2 = value.Value;
                        break;
                }
            }
            parser.Consume<MappingEnd>();
            return result;
        }
        return null;
    }

    public void WriteYaml(IEmitter emitter, object? value, Type type)
    {
        throw new NotImplementedException();
    }
}

I'm closing the issue, but if you need further help, let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants