我在方法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:对这个问题标题的任何建议?
答案 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);
}
}