2016-08-18 3 views
1

Ich habe eine Reihe von C# -Klassen, und viele von ihnen verwenden die DefaultValueAttribute, um UI-Hinweise für Bearbeitungszwecke aufzunehmen.Gibt es eine Möglichkeit, die Behandlung von DefaultValueAttributes zu deaktivieren?

Ich serialisieren Instanzen dieser Typen mit Json.NET und senden sie an einen JavaScript Client. Um die Bandbreite zu optimieren, möchte ich DefaultValueHandling.Ignore Option verwenden, ABER in einer Weise, dass es DefaultValueAttribute s nicht berücksichtigt. Mit anderen Worten, ich möchte nur die technischen Standardwerte false, 0, null ignorieren, aber keine vom Entwickler definierten Standardwerte.

Der Grund dafür ist, dass der JavaScript-Client keine Ahnung von speziellen, vom Entwickler definierten Standardwerten hat, sodass er nur die allgemeinen, oben genannten Standardwerte verarbeiten kann.

Gibt es eine Möglichkeit zum Ausschalten mit DefaultValueAttribute s?

+0

Entfernt das [tag: javascript] -Tag, die Frage ist rein über die C# -Seite der Dinge. –

+0

Ich bin mir nicht sicher, ob ich verstehe, was das Problem ist. DefaultValueAttribute wurde entwickelt, um von UI-Designern verwendet zu werden - es legt keine Standardwerte für die zugrunde liegende Klasse fest. Es sollte nicht von JsonSerializer serialisiert werden - können Sie ein Snippet des Json-Streams hinzufügen, der erzeugt wird, Hervorhebung des Problems in den Daten bitte – PhillipH

Antwort

1

können Sie erstellen ein custom contract resolver von DefaultContractResolver oder CamelCasePropertyNamesContractResolver erben, die die contract default value für die Eigenschaft zurück zu default(T) setzt:

public class NoDefaultValueContractResolver : DefaultContractResolver 
{ 
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons. 
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm 
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm 
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance." 
    static NoDefaultValueContractResolver instance; 

    // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit 
    static NoDefaultValueContractResolver() { instance = new NoDefaultValueContractResolver(); } 

    public static NoDefaultValueContractResolver Instance { get { return instance; } } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 

     if (property.AttributeProvider.GetAttributes(typeof(DefaultValueAttribute), true).Any()) 
     { 
      property.DefaultValue = property.PropertyType.GetDefaultValue(); 
     } 
     return property; 
    } 
} 

public static class TypeExtensions 
{ 
    public static object GetDefaultValue(this Type type) 
    { 
     if (type == null) 
      throw new ArgumentNullException("type"); 
     if (!type.IsValueType || Nullable.GetUnderlyingType(type) != null) 
      return null; 
     return Activator.CreateInstance(type, true); 
    } 
} 

es dann wie verwenden:

var settings = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore, ContractResolver = NoDefaultValueContractResolver.Instance }; 
var json = JsonConvert.SerializeObject(obj, settings); 

Durch einen benutzerdefinierten Vertrag Resolver Sie vermeiden die Notwendigkeit, Konverter für jeden Typ oder jedes Mitglied zu erstellen, das irgendwo einen DefaultValueAttribute hat.

+0

Danke, das ist eine nette Lösung. –

0

Interessant, dass Json.net DefaultValueAttribute verwendet - es sollte von visuellen Designoberflächen verwendet werden, nicht von Serialisierern. Ich würde das immer auf Ignorieren setzen.

Wenn Sie den Standardwert vor dem Serialisieren anwenden möchten, sollten Sie den Wert direkt vor der Deserialisierung festlegen. Sie können dies tun, indem Sie die Reflektion der Klasseninstanz verwenden, bevor Sie sie an den Serializer senden. Alternativ könnten Sie, wie hier vorgeschlagen, How do you modify the Json serialization of just one field using Json.net? Reflektion mit JsonConvert kombinieren, um den Wert abzufangen, bevor er in den Serializer geschrieben wird.

Verwandte Themen