2017-09-12 2 views
1

im bekommen StackOverflowException in Methode JsonTypeConverter.ConvertTo wenn Project.Settings.Default.Save()JsonConvert.SerializeObject + Typeconverter = Stackoverflow

Ich denke, ruft dies es ist, weil Methode Typeconverter vom Modelltyp erkennen JsonConvert.SerializeObject und ruft es intern ...

was ist der richtige Art und Weise dies zu schreiben? (Nur so kann ich mir vorstellen wird Zeichenfolge in Einstellungen zu speichern und tun Serialisierung/Deserialisierung manualy ...)

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; } 
    } 
} 

Inhalt von 'Eigenschaften/Settings.settings':

<?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: Irgendwelche Vorschläge für diesen Fragetitel?

Antwort

0

Das Problem ist, dass sowohl die JsonConverter und die Einstellungen Serializer das TypeConverter Attribut verwenden, um ihnen zu sagen, wie das Objekt zu serialisieren. Wenn JsonConverter versucht, das Objekt zu serialisieren, wird es sich am Ende selbst über Ihren benutzerdefinierten Konverter aufrufen und schließlich den Stapelüberlauf erhalten.

Um dies in Ihrem Konverter zu lösen, müssen Sie dem JsonConverter mitteilen, den Typ TypeConverterAttribute nicht zu verwenden und nur die Standardobjektserialisierung durchzuführen. Dies ist der Weg, den ich gefunden habe, um dies zu erreichen:

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); 
    } 
} 
Verwandte Themen