Json.NET自定义ValueProvider将对象转换为Guid [英] Json.NET Custom ValueProvider to convert Objects into Guid

查看:113
本文介绍了Json.NET自定义ValueProvider将对象转换为Guid的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为Json.NET创建一个自定义ValueProvider,它将跳过序列化所有对象的过程,而只是返回Guid类型的属性来表示其主键(作为参考).

I'm trying to create a custom ValueProvider for Json.NET that will skip serializing all the objects, and will just return a property of type Guid representing their primary Key instead (as a reference).

示例:

jsonData: {
    myObject: {
        id: "23e23-2gg5-6y666556-y6yg33",
        property2: ""
    }
}

应成为:

jsonData: {
    myObjectId: "23e23-2gg5-6y666556-y6yg33"
}

这是我到目前为止编写的代码.我非常接近使其工作,但是在我的CustomValueProvider中,我似乎无法获取对象值.我该怎么办?

This is the code I wrote so far. I'm very close to make it work, but in my CustomValueProvider I don't seem to be able to get the object values. How can I do that?

    private class CustomValueProvider : IValueProvider
    {
        private readonly MemberInfo _member;

        public CustomValueProvider(MemberInfo member)
        {
            _member = member;
        }
        public void SetValue(object target, object value)
        {
            throw new NotImplementedException();
        }

        public object GetValue(object target)
        {
            return // WHAT HERE??
        }
    }

    private class CustomResolver : CamelCasePropertyNamesContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var jsonProperty = base.CreateProperty(member, memberSerialization);

            if (jsonProperty.PropertyType.IsClass && jsonProperty.PropertyType != typeof(string))
            {
                jsonProperty = new JsonProperty
                {
                    PropertyName = member.Name.ToFirstCharLower() + "Id",
                    Readable = true,
                    ShouldSerialize = value => true,
                    PropertyType = typeof(Guid),
                    ValueProvider = new CustomValueProvider(member)
                };
            }

            return jsonProperty;
        }
    }

    private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
    {
        ContractResolver = new CustomResolver(),
        Formatting = Formatting.Indented
    };

推荐答案

您要将"Id"值从嵌套对象内部提升为父对象.为此,您需要将两个价值提供者链接在一起:

You want to promote the "Id" value from inside the nested object to the parent object. To do that, you're going to need to chain together two value providers:

  • 外部价值提供者,用于获取成员的价值.
  • 内部值提供程序,用于获取成员的Id的值.
  • An outer value provider to get the value of the member.
  • An inner value provider to get the value of the Id of the member.

以下操作是这样的:

class NestedValueProvider : IValueProvider
{
    readonly IValueProvider outerProvider;
    readonly IValueProvider innerProvider;

    public NestedValueProvider(IValueProvider outerProvider, IValueProvider innerProvider)
    {
        if (outerProvider == null || innerProvider == null)
            throw new ArgumentNullException();
        this.outerProvider = outerProvider;
        this.innerProvider = innerProvider;
    }
    public void SetValue(object target, object value)
    {
        throw new NotImplementedException();
    }

    public object GetValue(object target)
    {
        var innerTarget = outerProvider.GetValue(target);
        if (innerTarget == null)
            return null;
        return innerProvider.GetValue(innerTarget);
    }
}

class CustomResolver : CamelCasePropertyNamesContractResolver
{
    // Using an inner resolver prevents difficulties with recursion.
    readonly CamelCasePropertyNamesContractResolver innerResolver = new CamelCasePropertyNamesContractResolver();

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

        if (!jsonProperty.PropertyType.IsPrimitive && jsonProperty.PropertyType != typeof(string) && jsonProperty.Readable)
        {
            var innerContract = innerResolver.ResolveContract(jsonProperty.PropertyType);
            if (innerContract is JsonObjectContract)
            {
                var objectContract = (JsonObjectContract)innerContract;
                var idProperty = objectContract.Properties.GetClosestMatchProperty(ResolvePropertyName("Id"));
                if (idProperty != null && idProperty.Readable && (innerResolver.ResolveContract(idProperty.PropertyType) is JsonPrimitiveContract))
                {
                    jsonProperty = new JsonProperty
                    {
                        PropertyName = ResolvePropertyName(member.Name + "Id"),
                        Readable = true,
                        PropertyType = idProperty.PropertyType,
                        ValueProvider = new NestedValueProvider(jsonProperty.ValueProvider, idProperty.ValueProvider),
                    };
                }
            }
            // Possibly handle innerContract is JsonArrayContract?
            // Possibly handle innerContract is JsonDictionaryConract?
        }

        return jsonProperty;
    }
}

请注意使用内部合同解析器.这样可以防止递归调用递归类型时出现问题.

Note the use of an inner contract resolver. This prevents problems with recursive calls for recursive types.

您可能还想考虑处理具有ID的对象的集合或具有ID的对象的字典.例如,在以下对象中,List<MyObject>Dictionary<string, MyObject>属性将公开MyObject的内容:

You might also want to consider handling collections of objects with IDs, or dictionaries of objects with IDs. For instance in the following object, the List<MyObject> and Dictionary<string, MyObject> properties will expose contents of MyObject:

public class RootObject
{
    // Correctly not remapped
    public string StringValue { get; set; }

    // Correctly remaps to a GUID.
    public MyObject MyObject { get; set; }

    // Remap to a List<Guid> ?
    public List<MyObject> MyObjectList { get; set; }

    // Remap to a Dictionary<string, Guid> ?
    public Dictionary<string, MyObject> MyObjectDictionary { get; set; }
}

public class MyObject
{
    public Guid Id { get; set; }
    public string Property2 { get; set; }
}

这篇关于Json.NET自定义ValueProvider将对象转换为Guid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆