当前位置: 首页 > 面试题库 >

Json.NET自定义ValueProvider将对象转换为Guid

南宫奇思
2023-03-14
问题内容

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

例:

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

应成为:

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

这是我到目前为止编写的代码。我非常接近使其工作,但是就我而言,CustomValueProvider我似乎无法获取对象值。我怎样才能做到这一点?

    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"值从嵌套对象内部提升到父对象。为此,您需要将两个价值提供者链接在一起:

  • 一个外部值提供者,用于获取成员的值。
  • 一个内部值提供程序,用于获取Id成员的值。

以下是这样做的:

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

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

您可能还需要考虑处理具有ID的对象的集合或具有ID的对象的字典。例如在以下对象中,List<MyObject>and
Dictionary<string, MyObject>属性将公开以下内容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序列化一些对象,并且我想知道是否有一种简单的方法可以仅针对特定对象覆盖默认json.net转换器? 目前我有以下课程: JSON.NET当前将上述序列化为: 是否可以仅通过特定方式将其格式化为: 我对JSON.NET有点陌生。我想知道上面是否与编写自定义转换器有关。我找不到任何有关如何编写示例的具体示例。如果有人可以指出我的具体信息,我将不胜感激。 我需要找到

  • 我将springboot控制器与@RequestBody一起使用。我有以下json请求正文 我有一个对应的POJO 我有控制器就像 显然它不起作用,因为是请求中的字符串,而它在MyObject中是布尔值。我希望它有一个逻辑,所以如果在请求中,它将在MyObject中转换为布尔值。Spring有什么机制来实现这一点?

  • 使用代替和代替 然后在请求属性中添加 但是当我在javascript中检索它时,我得到了jsonObject的值 我在我的项目中已经使用了下面的库,如果需要,可以使用任何新的库

  • 这是我的字符串格式的肥皂xml,我需要如何在Farm对象中形成它。Farm是我的自定义类,任何库都是现成的 使用此代码后,我得到了异常 意外元素(uri:“http://yyyyyy . yyyyy * * * * * * * *”,local:“farm”)。预期的元素有

  • 我为jsf创建了一个自定义转换器。getAsObject()工作正常,但getAsString()返回异常。我不确定问题出在哪里,我尝试过用不同的方式将对象转换为字符串,但它不断返回异常。 这是我的代码: 这是Product类(为简单起见排除了getter/Setters/equals()/hash()): 这是stack我得到的: 这是我使用转换器的jsf:

  • 获取错误。我尝试做多个选择,并更改第二个选择的数据与第一个选择的上更改材料表行。我正在使用Firebase。 当“store.Urunler”为null或未定义时,我会出现此错误。而且我的产品没有列在菜单项上,这意味着选择是空的,但state.products有数据 我怎样才能克服这个错误。我还想添加到Urunler,选择一个输入。我知道我应该为onChanges调用函数,但如果它起作用,我以后会