【问题标题】:Custom JsonConverter for property: get property name属性的自定义 JsonConverter:获取属性名称
【发布时间】:2015-12-16 18:30:31
【问题描述】:

我有这个用于 guid 属性的示例转换器:

public class CustomGuidConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (Guid?) || objectType == typeof (Guid);
    }

    public override void WriteJson(JsonWriter writer, object oldValue, JsonSerializer serializer)
    {
        if (value != null)
        {
            var newValue = convert(oldValue); // do some conversion
            writer.WriteValue(newValue);
        }
    }
}

像这样使用它:

public class Outer {
    public int Id { get; set; }

    [JsonConverter(typeof(InterfaceLabelConverter))]
    public Guid? ProductFamilyId { get; set; }
}

如何在WriteJson 方法中访问当前属性的名称? 我想用这样的另一个属性名将旧值写入 writer:

{ Id: 1234, ProductFamilyId: 'newValue', ProductFamilyIdOld: 'oldValue' }

【问题讨论】:

  • 旧值从何而来?
  • 'oldGuid' 是需要序列化的实际值,'newGuid' 是否与您在问题中提到的转换后的值相同?
  • 您希望外部对象的 JSON 看起来像什么? IE。如果外部对象是public class Outer { public int Id { get; set; } public Guid? ProductFamilyId { get; set; } },那么应该生成什么JSON?

标签: c# json.net


【解决方案1】:

我建议将转换后的 GUID 设置为包含类的私有 get-only 属性。如果你用[JsonProperty] 标记它,它将被序列化:

public class Outer
{
    public int Id { get; set; }

    public Guid? ProductFamilyId { get; set; }

    [JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
    Guid? OldProductFamilyId
    {
        get
        {
            return Convert(ProductFamilyId);
        }
    }

    private Guid? Convert(Guid? guid)
    {
        if (guid != null)
        {
            var bytes = guid.Value.ToByteArray();
            bytes[0] = unchecked((byte)~bytes[0]); // For example
            guid = new Guid(bytes);
        }
        return guid;
    }
}

话虽如此,您可以从JsonWriter.Path 属性中选择当前属性名称:

public class InterfaceLabelConverter : JsonConverter
{
    private Guid? Convert(Guid? guid)
    {
        if (guid != null)
        {
            var bytes = guid.Value.ToByteArray();
            bytes[0] = unchecked((byte)~bytes[0]); // For example
            guid = new Guid(bytes);
        }
        return guid;
    }

    public override bool CanConvert(Type objectType)
    {
        throw new InvalidOperationException(); // This converter should only be applied directly to a property.
    }

    public override bool CanRead { get { return false; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var path = writer.Path;
        var propertyName = path.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Last(); // Throw an exception if not found.
        if (propertyName.StartsWith("[") && propertyName.EndsWith("]"))
            throw new InvalidOperationException(); // Trying to use this converter for an array element.
        var guid = (Guid?)value;
        writer.WriteValue(guid);

        if (guid != null)
        {
            // Note -- actually the converter isn't called for null values, see
            // https://stackoverflow.com/questions/8833961/serializing-null-in-json-net
            var nextGuid = Convert(guid);
            var nextName = "Old" + propertyName;

            writer.WritePropertyName(nextName);
            writer.WriteValue(nextGuid);
        }
    }
}

并像这样使用它:

public class Outer
{
    public int Id { get; set; }

    [JsonConverter(typeof(InterfaceLabelConverter))]
    public Guid? ProductFamilyId { get; set; }
}

【讨论】:

  • writer.Path 是缺失的部分,感谢空值处理提示。
  • 但是如何在没有 Newtonsoft 的情况下获取属性名称?
猜你喜欢
  • 2017-09-08
  • 1970-01-01
  • 2020-01-22
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-16
相关资源
最近更新 更多