Обрабатывать Double.NaN с Java на C# с помощью snapyaml (Java) и YamlDotNet (C#)

Я использую YAML для связи между графическим интерфейсом С# и Java на стороне сервера, который в целом работает нормально. Однако, если я передаю поле, которое является Double, и значением является Double.NaN на стороне Java, Yaml проходит как «.NaN», и когда я прихожу к десериализации на стороне C#, «System.FormatException» выдается как C# ожидает строку "NaN" [не ".NaN"].

Кто-нибудь знает, есть ли способ перехватить десериализатор или добавить форматирование, чтобы на стороне С# ".NaN" можно было проанализировать в двойном?

(Одним из обходных путей, который я могу придумать, является изменение всех NaN на специальное значение перед серлиазом в YAML, а затем на С# распознавание специального значения и преобразование обратно в NaN, но это похоже на большой взлом.)


person Chill    schedule 23.09.2015    source источник
comment
Я нашел эту ссылку и заметил, что после применения следующего работало: Double.Parse(.NaN), однако кажется, что YamlDotNet создает свой собственный NumberFormatInfo ссылка, поэтому я думаю, что реальный вопрос заключается в том, как переопределить NumberFormatInfo, используемый в YamlDotNet. Любые идеи?   -  person Chill    schedule 23.09.2015


Ответы (1)


Кажется, это ошибка в том, как YamlDotNet обрабатывает числа с плавающей запятой. Пока это не будет исправлено, вы можете обойти это, зарегистрировав пользовательский узел INodeDeserializer, который будет обрабатывать эти особые случаи.

Вот быстрая и грязная реализация такого десериализатора:

public class FloatNodeDeserializer : INodeDeserializer
{
    private static readonly Dictionary<Tuple<Type, string>, object> SpecialFloats =
        new Dictionary<Tuple<Type, string>, object>
    {
        { Tuple.Create(typeof(float), ".nan"), float.NaN },
        { Tuple.Create(typeof(float), ".inf"), float.PositiveInfinity },
        { Tuple.Create(typeof(float), "-.inf"), float.NegativeInfinity },

        { Tuple.Create(typeof(double), ".nan"), double.NaN },
        { Tuple.Create(typeof(double), ".inf"), double.PositiveInfinity },
        { Tuple.Create(typeof(double), "-.inf"), double.NegativeInfinity },
    };

    bool INodeDeserializer.Deserialize(
        EventReader reader,
        Type expectedType,
        Func<EventReader, Type, object> nestedObjectDeserializer,
        out object value
    ) {
        var scalar = reader.Peek<Scalar>();
        if (scalar == null) {
            value = null;
            return false;
        }

        var found = SpecialFloats.TryGetValue(
            Tuple.Create(expectedType, scalar.Value),
            out value);

        if(found) {
            reader.Allow<Scalar>();
        }
        return found;
    }
}

Способ регистрации такой:

var deserializer = new Deserializer();
deserializer.NodeDeserializers.Insert(0, new FloatNodeDeserializer());

Полностью работающая скрипта здесь

person Antoine Aubry    schedule 24.09.2015
comment
Фантастический! Спасибо, Антуан. К вашему сведению, мне пришлось внести очень небольшое изменение в FloatNodeDeserializer. При получении из словаря я помещал scalar.Value.ToLower(), поскольку значение было .NaN, поэтому .nan не был найден. Ценим ваш быстрый ответ! - person Chill; 24.09.2015