首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JsonConverter和EntityData

JsonConverter和EntityData
EN

Stack Overflow用户
提问于 2017-09-22 18:50:15
回答 1查看 288关注 0票数 2

我使用Azure的数据库优先EF方法。Azure web服务中我的一个实体的定义如下:

代码语言:javascript
复制
public class Company : EntityData
{
    public string CompanyName { get; set; }
}

它从EntityData继承Id属性。Id属性的类型为字符串。

在客户端,我有以下实体:

代码语言:javascript
复制
class Company
{
    [JsonConverter(typeof(IntConverter))]
    public int Id { get; set; }

    public string CompanyName { get; set; }
}

正如您在上面看到的,我需要将Id从string转换为int。

我创建了以下JSON转换器:

代码语言:javascript
复制
class IntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null)
            return 0;

        int num;
        if (Int32.TryParse(reader.Value.ToString(), out num))
            return num;
        else
            return 0;
    }

    public override void WriteJson(JsonWriter writer, object value, 
        JsonSerializer serializer)
    {
        serializer.Serialize(writer, value.ToString());
    }
}

它运行良好,但由于这是我的第一个JSON转换器,我不确定是否正确地创建了它。我看到了转换器的例子,它们使用的是existingValue而不是reader.Value。在我的例子中,existingValue总是0。

上述实施是否正确?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-22 20:31:33

你的代码基本上是正确的。

existingValue是以前存在于父c#模型中的值。通过将其传递到转换器中,Json.NET允许转换器在人口现有模型或只读集合时工作。例如,如果您的转换器具有预分配的只读属性:

代码语言:javascript
复制
public class RootObject
{
    readonly ObservableCollection<SomeClass> _collection = new ObservableCollection<SomeClass>();

    [JsonConverter(typeof(ObservableCollectionConverter<SomeClass>>)]
    public ObservableCollection<SomeClass> { get { return _collection; } }
}

然后,ReadJson()方法ObservableCollectionConverter<SomeClass>将传递预分配的_collection值,并能够将项添加到其中。

尽管如此,仍有一些改进需要改进:

  1. WriteJson()中,你叫value.ToString()。有可能ToString()可以返回特定于文化的字符串,例如小数点可能被插入到NumberGroupSeparator中。相反,您应该按照以下方式在不变格式中序列化: 公共覆盖WriteJson(JsonWriter writer,object value,JsonSerializer序列化程序){ // Int32实现了具有ToString()重载//采用IFormatProvider规范的IConvertible接口。传递不变格式以保证//相同的序列化在所有区域性中。变量可兑换=(IConvertible)值;serializer.Serialize(writer,IConvertible}
  2. 需要在ReadJson()中进行类似的修复: 如果(Int32.TryParse(reader.Value.ToString(),NumberStyles.Integer,NumberFormatInfo.InvariantInfo,out num))返回num,否则返回0;
  3. 您的ReadJson()无法抵御意外数据。例如,如果传入的JSON实际上有一个数组或对象值(例如{"unexpectedProperty": "unexpectedValue"}),那么JsonReader将不能正确地提前到输入的末尾。您应该检查reader.TokenType并适当地处理坏数据,例如: 公共覆盖对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序){ switch (reader.TokenType) { case JsonToken.Null:返回null;case JsonToken.Integer: // Input已经是一个整数。返回它返回( int )JToken.Load(读取器);大小写JsonToken.String:{int num;if (Int32.TryParse(reader.Value.ToString(),NumberStyles.Integer,NumberFormatInfo.InvariantInfo,out num))返回num;否则返回0;} default:在路径{1}",reader.TokenType,reader.Path)抛出新的reader.TokenType令牌{0} );} 或者,如果您喜欢在不引发异常的情况下使用和丢弃意外数据(我不建议这样做),则可以使用JsonReader.Skip(): 默认值:Debug.WriteLine(string.Format(路径{1}处的“意外令牌{0}”,reader.TokenType,reader.Path));reader.Skip();返回0;
  4. 当通过属性应用转换器时,不会调用JsonConverter.CanConvert。但是,如果将转换器添加到JsonSerializerSettings.Converters中,那么从CanConvert返回true将是一个问题。相反,我建议要么抛出一个NotImplementedException,要么正确地实现该方法: 公共覆盖bool CanConvert( objectType类型){返回objectType ==类型(Int)\x objectType ==类型(int?);}

因此,您的最终转换器可能如下所示:

代码语言:javascript
复制
class IntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(int) || objectType == typeof(int?);
    }

    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        switch (reader.TokenType)
        {
            case JsonToken.Null:
                return null;

            case JsonToken.Integer:
                // Input was already an integer.  Return it
                return (int)JToken.Load(reader);

            case JsonToken.String:
                {
                    int num;
                    if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
                        return num;
                    else
                        return 0;
                }

            default:
                throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
        }
    }

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        // Int32 implements the IConvertible interface which has a ToString() overload
        // that takes an IFormatProvider specification.  Pass the invariant format to guarantee
        // identical serialization in all cultures.
        var convertible = (IConvertible)value;
        serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
    }
}

示例小提琴显示了最终转换器的严格版本和容忍版本。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46371420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档