亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Json.NET 中僅一個屬性的自定義序列化程序,無需更改模型類

Json.NET 中僅一個屬性的自定義序列化程序,無需更改模型類

C#
一只斗牛犬 2022-06-12 15:15:15
我需要做類似以下的事情,但我需要在不將屬性放在模型類上或以其他方式污染模型類的情況下這樣做。理想的解決方案將通過 . 工作JsonSerializerSettings,而不會干擾其他自定義序列化。public class Person{    public string FirstName { get; set; }    [JsonConverter(typeof(AllCapsConverter))]    public string LastName { get; set; }    // more properties here in the real example, some of which nest to properties that use their own JsonConverters.}對于JsonConverter這個玩具示例(內容并不真正相關;相關的是我將它用于屬性):public class AllCapsConverter : JsonConverter{    public override bool CanConvert(Type objectType)        => objectType == typeof(string);    public override bool CanRead => false;    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)    {        throw new NotSupportedException();    }    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)    {        var str = value as string;        var upper = str.ToUpperInvariant();        JToken j = JToken.FromObject(upper);        j.WriteTo(writer);    }}通過單元測試:public class PersonSerializationTest{    [Fact]    public void SerializePerson_LastNameCaps()    {        var person = new Person        {            FirstName = "George",            LastName = "Washington"        };        var serialized = JsonConvert.SerializeObject(person);        var expected = @"{""FirstName"":""George"",""LastName"":""WASHINGTON""}";        Assert.Equal(expected, serialized);    }}
查看完整描述

2 回答

?
慕尼黑5688855

TA貢獻1848條經驗 獲得超2個贊

您可以以編程方式將 aJsonConverter應用于模型類中的一個或多個屬性,而無需通過 custom 使用屬性ContractResolver。這是一個簡單的示例,它將您應用于您班級AllCapsConverter中的LastName財產。Person(如果您正在尋找更強大的解決方案,請查看@dbc 的答案。我的目的是展示可能可行的最簡單示例。)


public class CustomResolver : DefaultContractResolver

{

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

    {

        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        if (prop.DeclaringType == typeof(Person) && prop.UnderlyingName == "LastName")

        {

            prop.Converter = new AllCapsConverter();

        }

        return prop;

    }

}

這是更新的測試和Person模型,顯示了如何使用解析器:


public class PersonSerializationTest

{

    [Fact]

    public void SerializePerson_LastNameCaps()

    {

        var person = new Person

        {

            FirstName = "George",

            LastName = "Washington"

        };

        var settings = new JsonSerializerSettings

        {

            ContractResolver = new CustomResolver()

        };

        var serialized = JsonConvert.SerializeObject(person, settings);

        var expected = @"{""FirstName"":""George"",""LastName"":""WASHINGTON""}";

        Assert.Equal(expected, serialized);

    }

}


public class Person

{

    public string FirstName { get; set; }

    public string LastName { get; set; }

}


查看完整回答
反對 回復 2022-06-12
?
溫溫醬

TA貢獻1752條經驗 獲得超4個贊

您可以使用從IContractResolverDefaultContractResolver.


首先,ConfigurableContractResolver從這個答案中獲取如何添加元數據來描述 JSON.Net 中哪些屬性是日期:


public class ConfigurableContractResolver : DefaultContractResolver

{

    // This contract resolver taken from the answer to

    // https://stackoverflow.com/questions/46047308/how-to-add-metadata-to-describe-which-properties-are-dates-in-json-net

    // https://stackoverflow.com/a/46083201/3744182


    readonly object contractCreatedPadlock = new object();

    event EventHandler<ContractCreatedEventArgs> contractCreated;

    int contractCount = 0;


    void OnContractCreated(JsonContract contract, Type objectType)

    {

        EventHandler<ContractCreatedEventArgs> created;

        lock (contractCreatedPadlock)

        {

            contractCount++;

            created = contractCreated;

        }

        if (created != null)

        {

            created(this, new ContractCreatedEventArgs(contract, objectType));

        }

    }


    public event EventHandler<ContractCreatedEventArgs> ContractCreated

    {

        add

        {

            lock (contractCreatedPadlock)

            {

                if (contractCount > 0)

                {

                    throw new InvalidOperationException("ContractCreated events cannot be added after the first contract is generated.");

                }

                contractCreated += value;

            }

        }

        remove

        {

            lock (contractCreatedPadlock)

            {

                if (contractCount > 0)

                {

                    throw new InvalidOperationException("ContractCreated events cannot be removed after the first contract is generated.");

                }

                contractCreated -= value;

            }

        }

    }


    protected override JsonContract CreateContract(Type objectType)

    {

        var contract = base.CreateContract(objectType);

        OnContractCreated(contract, objectType);

        return contract;

    }

}


public class ContractCreatedEventArgs : EventArgs

{

    public JsonContract Contract { get; private set; }

    public Type ObjectType { get; private set; }


    public ContractCreatedEventArgs(JsonContract contract, Type objectType)

    {

        this.Contract = contract;

        this.ObjectType = objectType;

    }

}


public static class ConfigurableContractResolverExtensions

{

    public static ConfigurableContractResolver Configure(this ConfigurableContractResolver resolver, EventHandler<ContractCreatedEventArgs> handler)

    {

        if (resolver == null || handler == null)

            throw new ArgumentNullException();

        resolver.ContractCreated += handler;

        return resolver;

    }

}

然后,創建一個方法來配置JsonObjectContractfor Person,如下所示:


public static class JsonContractExtensions

{

    public static void ConfigurePerson(this JsonContract contract)

    {

        if (!typeof(Person).IsAssignableFrom(contract.UnderlyingType))

            return;

        var objectContract = contract as JsonObjectContract;

        if (objectContract == null)

            return;

        var property = objectContract.Properties.Where(p => p.UnderlyingName == nameof(Person.LastName)).Single();

        property.Converter = new AllCapsConverter();

    }

}

最后序列化如下:


// Cache the contract resolver statically for best performance.

var resolver = new ConfigurableContractResolver()

    .Configure((s, e) => { e.Contract.ConfigurePerson(); });


var settigs = new JsonSerializerSettings

{

    ContractResolver = resolver,

};


var person = new Person

{

    FirstName = "George",

    LastName = "Washington"

};

var serialized = JsonConvert.SerializeObject(person, settigs);

筆記:


ConfigurableContractResolver與其創建它,不如對那里的必要邏輯進行子類化DefaultContractResolver、覆蓋DefaultContractResolver.CreateProperty和硬編碼Person.LastName。然而,創建一個允許在運行時組合定制的可配置解析器似乎更有用且可重用。


用它來寫你的大寫字符串AllCapsConverter.WriteJson()會更簡單:writer.WriteValue(string)


public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)

{

    var upper = ((string)value).ToUpperInvariant();

    writer.WriteValue(upper);

}

您可能希望緩存合約解析器以獲得最佳性能。


查看完整回答
反對 回復 2022-06-12
  • 2 回答
  • 0 關注
  • 187 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號