JsonConvert.SerializeObject + TypeConverter = StackOverflowException

时间:2017-09-12 23:28:09

标签: c#

我在方法StackOverflowException中获取JsonTypeConverter.ConvertTo 致电Project.Settings.Default.Save()

我认为这是因为方法JsonConvert.SerializeObject在模型类型上检测到typeconverter并在内部调用它...

这是写这个的正确方法吗? (我能想到的唯一方法是在设置中存储字符串并手动进行序列化/反序列化...)

public class JsonTypeConverter<TModel> : TypeConverter
{
    #region Overrides of TypeConverter

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string strValue) {
            return JsonConvert.DeserializeObject<TModel>(strValue);
        }

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is TModel model) {
            return JsonConvert.SerializeObject(model, Formatting.None);
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    #endregion
}

namespace Model {

    [TypeConverter(typeof(JsonTypeConverter<DataModel>))]
    [SettingsSerializeAs(SettingsSerializeAs.String)]
    public class DataModel {
        public string Value { get; set; }
    }
}

属性/设置。内容&#39;:

<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Builder.Properties" GeneratedClassName="Settings">
    <Profiles />
    <Settings>
        <Setting Name="DataSource" Type="Model.DataModel" Scope="User">
            <Value Profile="(Default)" />
        </Setting>
    </Settings>
</SettingsFile>

PS:对这个问题标题的任何建议?

1 个答案:

答案 0 :(得分:1)

问题是JsonConverter和设置序列化程序都使用TypeConverter属性来告诉他们如何序列化对象。当JsonConverter尝试序列化对象时,它将最终通过自定义转换器再次调用自身,并最终获得堆栈溢出。

要在转换器中解决此问题,您必须告诉JsonConverter不要使用类型TypeConverterAttribute并且只执行默认对象序列化。这是我发现实现这一目标的方式:

public class JsonTypeConverter<TModel> : TypeConverter
{
    /* rest of your class ... */

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string strValue)
        {
            return JsonConvert.DeserializeObject<TModel>(strValue, new JsonSerializerSettings
            {
                ContractResolver = new CustomContractResolver(),
            });
        }

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is TModel model)
        {
            return JsonConvert.SerializeObject(model, new JsonSerializerSettings
            {
                ContractResolver = new CustomContractResolver(),
            });
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }
}     

class CustomContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (typeof(DataModel).IsAssignableFrom(objectType))
        {
            return this.CreateObjectContract(objectType);
        }
        return base.CreateContract(objectType);
    }
}