JavaScriptSerializer – 自定义属性名称

我正在使用JavaScriptSerializer来反序列化json数据。 一切都很好,但我的问题是,json数据中的一个属性被命名为“base”,所以我不能在我的C#代码中创建这样的属性。 我发现我可以手动将值映射到构造函数中的属性,但问题是,我的DTO有200个属性,所以我不想手动制作,而是希望找到任何其他解决方案。 我也尝试使用注释,但这个:

[JsonProperty("base")] public int baseValue { get; set; } 

没有帮助我,值baseValue每次设置为0(如果你认为,这个注释应该工作,我可以发布我的整个代码,不仅这2行)

有什么办法可以简单地解决我的问题吗?

回答几个部分:

  1. 要创建名为base的属性,需要在名称前加上@

     public int @base { get; set; } 
  2. 您写道您正在使用JavaScriptSerializer 。 属性[JsonProperty]用于完全不同的序列化程序Json.NET 。 此属性对JavaScriptSerializer没有影响。

    如果要切换到Json.NET,则可以使用此属性。

  3. 事实上, JavaScriptSerializer无法在编写自定义JavaScriptConverter之外重命名属性以进行序列化。 这个序列化器非常简单; 它支持的唯一序列化属性是ScriptIgnore来抑制属性的序列化。

正如dbc所写, JavaScriptSerializer非常有限。 由于我们不能在项目中使用Json.NET ,因此我编写了一个名为CustomJavaScriptSerializer的JavaScriptConverter来增强JavaScriptSerializer。

不幸的是,由于JavaScriptConverter和JavaScriptSerializer一起工作的方式(本来可以做得更好,微软!),有必要派生你的类从CustomJavaScriptSerializer序列化。 这是唯一的限制。

但是,您可以完全控制和灵活地处理类的序列化/反序列化。 一些方便的function已经很成功,比如对JsonProperty的部分支持或者对所有属性名称的第一个字母进行下限(因为它是JavaScript中的惯例)。 有关确切用法和所有function,请参阅代码中的注释。 除此之外,您还可以覆盖任何派生类中的序列化方法,以微调特定于该特定类的序列化。

虽然我认为课程非常可靠,但一如既往,我不承担任何责任。 使用风险自负。

那就是说,这是代码:

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Web.Script.Serialization; namespace SomeNamespace { #region Class CustomJavaScriptSerializer ///  /// Custom JavaScript serializer, see https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptconverter%28v=vs.110%29.aspx ///  ///  /// Used to enhance functionality of standard . /// Eg to support  that provides some properties known from Newtonsoft's JavaScript serializer, /// see https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonPropertyAttribute.htm. /// Additionally, there is an attribute  that can be applied to the class /// to manipulate JSON serialization behavior of all properties of the class. /// Use this JSON serializer when including Newtonsoft's JavaScript serializer is not an option for you. /// /// Usage: /// /// - Just derive your class to be JSON serialized / deserialized from this class. /// - You now can decorate the properties of your class with eg [JsonProperty( "someName" )]. See  for details. /// - Additionally, you can decorate your class with eg [JsonClass( DoNotLowerCaseFirstLetter = true)]. See  for details. /// - Important! Use static methods  and  of this class for JSON serialization / deserialization. /// - For further customization specific to your class, you can override  and  in your derived class. /// /// Example: /// ///  /// /// The tooltip. Will be transferred to JavaScript as "tooltext". /// ///  /// [JsonProperty( "tooltext" )] /// public string Tooltip /// { /// get; /// set; /// } /// /// ... /// } /// /// ]]> ///  public abstract class CustomJavaScriptSerializer : JavaScriptConverter { #region Fields ///  /// Dictionary to collect all derived  to be registered with  ///  private static Dictionary convertersToRegister = new Dictionary(); ///  /// Sync for . ///  private static readonly object sync = new object(); #endregion #region Properties ///  /// All derived  to be registered with  ///  public static IEnumerable ConvertersToRegister { get { return CustomJavaScriptSerializer.convertersToRegister.Values; } } ///  ///  retrieved from decoration of the derived class. ///  ///  /// Is only set when an instance of this class is used for serialization. See constructor for details. ///  protected JsonClassAttribute ClassAttribute { get; private set; } #endregion #region Constructors ///  /// Default constructor ///  public CustomJavaScriptSerializer() { Type type = this.GetType(); if ( CustomJavaScriptSerializer.convertersToRegister.ContainsKey( type ) ) return; lock( sync ) { // Remember this CustomJavaScriptSerializer instance to do serialization for this type. if ( CustomJavaScriptSerializer.convertersToRegister.ContainsKey( type ) ) return; // Performance: Set ClassAttribute only for the instance used for serialization. this.ClassAttribute = ( this.GetType().GetCustomAttributes( typeof( JsonClassAttribute ), true ).FirstOrDefault() as JsonClassAttribute ) ?? new JsonClassAttribute(); convertersToRegister[ type ] = this; } } #endregion #region Public Methods ///  /// Converts  to a JSON string. ///  /// The object to serialize. /// The serialized JSON string. public static string JsonSerialize( object obj ) { var serializer = new JavaScriptSerializer(); serializer.RegisterConverters( CustomJavaScriptSerializer.ConvertersToRegister ); serializer.MaxJsonLength = int.MaxValue; return serializer.Serialize( obj ); } ///  /// Converts a JSON-formatted string to an object of the specified type. ///  /// The JSON string to deserialize. /// The type of the resulting object. /// The deserialized object. public static object JsonDeserialize( string input, Type targetType ) { var serializer = new JavaScriptSerializer(); serializer.RegisterConverters( CustomJavaScriptSerializer.ConvertersToRegister ); serializer.MaxJsonLength = int.MaxValue; return serializer.Deserialize( input, targetType ); } ///  /// Converts the specified JSON string to an object of type . ///  /// The type of the resulting object. /// The JSON string to be deserialized. /// The deserialized object. public static T JsonDeserialize( string input ) { return (T)CustomJavaScriptSerializer.JsonDeserialize( input, typeof( T ) ); } ///  /// Get this object serialized as JSON string. ///  /// This object as JSON string. public string ToJson() { return CustomJavaScriptSerializer.JsonSerialize( this ); } #endregion #region Overrides ///  /// Return list of supported types. This is just a derived class here. ///  [ScriptIgnore] public override IEnumerable SupportedTypes { get { return new ReadOnlyCollection( new List(){ this.GetType() } ); } } ///  /// Serialize the passed . ///  /// The object to serialize. /// The  calling this method. /// A dictionary with name value pairs representing property name value pairs as they shall appear in JSON.  public override IDictionary Serialize( object obj, JavaScriptSerializer serializer ) { var result = new Dictionary(); if ( obj == null ) return result; BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; PropertyInfo[] properties = this.GetType().GetProperties( bindingFlags ); foreach ( PropertyInfo property in properties ) { KeyValuePair kvp = this.GetSerializedProperty( obj, property ); if ( !string.IsNullOrEmpty( kvp.Key ) ) result[ kvp.Key ] = kvp.Value; } return result; } ///  /// Deserialize  to . ///  ///  /// Reverse method to  ///  /// The dictionary to be deserialized. /// Type to deserialize to. This is the type of the derived class, see . /// The  calling this method. /// An object of type  with property values set from . public override object Deserialize( IDictionary dictionary, Type type, JavaScriptSerializer serializer ) { if ( dictionary == null ) throw new ArgumentNullException( "dictionary" ); if ( type == null ) throw new ArgumentNullException( "type" ); if ( serializer == null ) throw new ArgumentNullException( "serializer" ); // This will fail if type has no default constructor. object result = Activator.CreateInstance( type ); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; PropertyInfo[] properties = this.GetType().GetProperties( bindingFlags ); foreach ( PropertyInfo property in properties ) { this.SetDerializedProperty( result, property, dictionary, serializer ); } return result; } #endregion #region Protected Methods ///  /// Get a key value pair as base for serialization, based on the passed . ///  ///  /// The returned  key represents the property's name in JSON, the value its value. ///  /// The object to serialize. /// The To be serialized. /// The requested key value pair or an empty key value pair (key = null) to ignore this property. protected virtual KeyValuePair GetSerializedProperty( object obj, PropertyInfo property ) { var result = new KeyValuePair(); if ( property == null || !property.CanRead ) return result; object value = property.GetValue( obj ); if ( value == null && !this.ClassAttribute.SerializeNullValues ) return result; JsonPropertyAttribute jsonPropertyAttribute = this.GetJsonPropertyAttribute( property ); if ( jsonPropertyAttribute == null || jsonPropertyAttribute.Ignored ) return result; if ( value != null && jsonPropertyAttribute.UseToString ) value = value.ToString(); string name = jsonPropertyAttribute.PropertyName; return new KeyValuePair( name, value ); } ///  /// Set  of  with value provided in . ///  /// The object to set . /// The property to set its value. /// Dictionary with property name - value pairs to query for  value. /// The  calling this method. public virtual void SetDerializedProperty( object obj, PropertyInfo property, IDictionary dictionary, JavaScriptSerializer serializer ) { if ( obj == null || property == null || !property.CanWrite || dictionary == null || serializer == null ) return; JsonPropertyAttribute jsonPropertyAttribute = this.GetJsonPropertyAttribute( property ); if ( jsonPropertyAttribute == null || jsonPropertyAttribute.Ignored || jsonPropertyAttribute.UseToString ) return; string name = jsonPropertyAttribute.PropertyName; if ( !dictionary.ContainsKey( name ) ) return; object value = dictionary[ name ]; // Important! Use JavaScriptSerializer.ConvertToType so that CustomJavaScriptSerializers of properties of this class are called recursively. object convertedValue = serializer.ConvertToType( value, property.PropertyType ); property.SetValue( obj, convertedValue ); } ///  /// Gets a  for the passed . ///  /// The property to examine. May not be null. /// A  with properties set to be used directly as is, never null. protected JsonPropertyAttribute GetJsonPropertyAttribute( PropertyInfo property ) { if ( property == null ) throw new ArgumentNullException( "property" ); object[] attributes = property.GetCustomAttributes( true ); JsonPropertyAttribute jsonPropertyAttribute = null; bool ignore = false; foreach ( object attribute in attributes ) { if ( attribute is ScriptIgnoreAttribute ) ignore = true; if ( attribute is JsonPropertyAttribute ) jsonPropertyAttribute = (JsonPropertyAttribute)attribute; } JsonPropertyAttribute result = jsonPropertyAttribute ?? new JsonPropertyAttribute(); result.Ignored |= ignore; if ( string.IsNullOrWhiteSpace( result.PropertyName ) ) result.PropertyName = property.Name; if ( !this.ClassAttribute.DoNotLowerCaseFirstLetter && ( jsonPropertyAttribute == null || string.IsNullOrWhiteSpace( jsonPropertyAttribute.PropertyName ) ) ) { string name = result.PropertyName.Substring( 0, 1 ).ToLowerInvariant(); if ( result.PropertyName.Length > 1 ) name += result.PropertyName.Substring( 1 ); result.PropertyName = name; } return result; } #endregion } #endregion #region Class JsonClassAttribute ///  /// Attribute to be used in conjunction with . ///  ///  /// Decorate your class derived from  with this attribute to /// manipulate how JSON serialization / deserialization is done for all properties of your derived class. ///  [AttributeUsage( AttributeTargets.Class )] public class JsonClassAttribute : Attribute { #region Properties ///  /// By default, all property names are automatically converted to have their first letter lower case (as it is convention in JavaScript). Set this to true to avoid that behavior. ///  public bool DoNotLowerCaseFirstLetter { get; set; } ///  /// By default, properties with value null are not serialized. Set this to true to avoid that behavior. ///  public bool SerializeNullValues { get; set; } #endregion } #endregion #region Class JsonPropertyAttribute ///  /// Attribute to be used in conjunction with . ///  ///  /// Among others, used to define a property's name when being serialized to JSON. /// Implements some functionality found in Newtonsoft's JavaScript serializer, /// see https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonPropertyAttribute.htm ///  [AttributeUsage( AttributeTargets.Property )] public class JsonPropertyAttribute : Attribute { #region Properties ///  /// True to ignore this property. ///  public bool Ignored { get; set; } ///  /// Gets or sets the name of the property. ///  public string PropertyName { get; set; } ///  /// When true, the value of this property is serialized using value.ToString(). ///  ///  /// Can be handy when serializing eg enums or types. /// Do not set this to true when deserialization is needed, since there is no general inverse method to ToString(). /// When this is true, the property is just ignored when deserializing. ///  public bool UseToString { get; set; } #endregion #region Constructors ///  /// Default constructor ///  public JsonPropertyAttribute() { } ///  /// Initializes a new instance of the  class with the specified name. ///  /// Name of the property public JsonPropertyAttribute( string propertyName ) { this.PropertyName = propertyName; } #endregion } #endregion } 

并进行unit testing:

 #region CustomJavaScriptSerializer /// Tests behavior of CustomJavaScriptSerializer. [TestMethod] public void TestCustomJavaScriptSerializer() { // 11 var dataItem11 = new JsonSerializeTest1(); dataItem11.Label = "LabelName"; dataItem11.Value = 5; dataItem11.Test = TestEnum.B; dataItem11.Tooltip = "TooltipName"; string json11 = dataItem11.ToJson(); Assert.IsTrue( json11 == "{\"label\":\"LabelName\",\"value\":5,\"test\":2,\"tooltext\":\"TooltipName\"}" ); JsonSerializeTest1 deserialized11 = CustomJavaScriptSerializer.JsonDeserialize( json11 ); Assert.IsNotNull( deserialized11 ); Assert.IsTrue( deserialized11.Equals( dataItem11 ) ); // 12 var dataItem12 = new JsonSerializeTest1(); dataItem12.Value = 5; dataItem12.Test = TestEnum.A; dataItem12.Tooltip = "TooltipName"; string json12 = dataItem12.ToJson(); Assert.IsTrue( json12 == "{\"value\":5,\"test\":1,\"tooltext\":\"TooltipName\"}" ); JsonSerializeTest1 deserialized12 = CustomJavaScriptSerializer.JsonDeserialize( json12 ); Assert.IsNotNull( deserialized12 ); Assert.IsTrue( deserialized12.Equals( dataItem12 ) ); // 21 var dataItem21 = new JsonSerializeTest2(); dataItem21.Label = "LabelName"; dataItem21.Value = 5; dataItem21.Test = TestEnum.B; dataItem21.Tooltip = "TooltipName"; string json21 = dataItem21.ToJson(); Assert.IsTrue( json21 == "{\"Test\":\"B\",\"Label\":\"LabelName\",\"Value\":5}" ); JsonSerializeTest2 deserialized21 = CustomJavaScriptSerializer.JsonDeserialize( json21 ); Assert.IsNotNull( deserialized21 ); Assert.IsTrue( deserialized21.Label == "LabelName" ); Assert.IsTrue( deserialized21.Value == 5 ); // No mistake! UseToString = true here. See JsonPropertyAttribute.UseToString. Assert.IsTrue( deserialized21.Test == 0 ); Assert.IsTrue( deserialized21.Tooltip == null ); // 22 var dataItem22 = new JsonSerializeTest2(); dataItem22.Tooltip = "TooltipName"; string json22 = dataItem22.ToJson(); Assert.IsTrue( json22 == "{\"Test\":\"0\",\"Label\":null,\"Value\":null}" ); JsonSerializeTest2 deserialized22 = CustomJavaScriptSerializer.JsonDeserialize( json22 ); Assert.IsNotNull( deserialized22 ); Assert.IsTrue( deserialized22.Label == null ); Assert.IsTrue( deserialized22.Value == null ); Assert.IsTrue( deserialized22.Test == 0 ); Assert.IsTrue( deserialized22.Tooltip == null ); var list = new List() { dataItem11, dataItem12 }; var json = CustomJavaScriptSerializer.JsonSerialize( list ); List deserialized = CustomJavaScriptSerializer.JsonDeserialize>( json ); Assert.IsNotNull( deserialized ); Assert.IsTrue( deserialized.Count == 2 ); Assert.IsTrue( deserialized[ 0 ].Equals( deserialized11 ) ); Assert.IsTrue( deserialized[ 1 ].Equals( deserialized12 ) ); } [JsonClass( DoNotLowerCaseFirstLetter = true, SerializeNullValues = true )] public class JsonSerializeTest2 : JsonSerializeTest1 { ///  /// A tooltip ///  [JsonProperty( Ignored = true )] public override string Tooltip { get; set; } ///  /// An enum ///  [JsonProperty( UseToString = true )] public override TestEnum Test { get; set; } } public class JsonSerializeTest1 : CustomJavaScriptSerializer { ///  /// A label ///  public virtual string Label { get; set; } ///  /// A Value ///  public virtual decimal? Value { get; set; } ///  /// An enum ///  public virtual TestEnum Test { get; set; } ///  /// A tooltip ///  [JsonProperty( "tooltext" )] public virtual string Tooltip { get; set; } ///  /// Whether this object is the same as . ///  /// True =  is the same as this object, false otherwise. public override bool Equals( object obj ) { var other = obj as JsonSerializeTest1; // Cast to object to avoid that it calls overridden == operator here. if ( (object)other == null ) return false; return this.Label == other.Label && this.Value == other.Value && this.Test == other.Test && this.Tooltip == other.Tooltip; } ///  /// Get hash code for comparison ///  public override int GetHashCode() { return base.GetHashCode(); } } public enum TestEnum { A = 1, B = 2 } #endregion 

请享用!