Newtonsoft.Json DeserializeObject为guid 00000000-0000-0000-0000-000000000000传递null

时间:2014-11-22 15:10:06

标签: c# json json.net json-deserialization

我有一个用于表示身份的类,它包含一个字符串值。

然后我有另一个用于表示事件的类,包括一个标识对象和一个字符串名称。

我可以从对象序列化到JSON字符串,我得到字符串:

{"Id":{"Value":"2e4146c2-66c9-4637-8936-29ccfc5df638"},"Name":"Jon Doe"}

但是,当我从上面的JSON转到object时,在MyIdentity构造函数中,字符串identityValue作为"00000000-0000-0000-0000-000000000000"传入。

我也试过为MyIdentity提供两个构造函数,一个用于字符串,一个用于Guid,但结果相同。这背后的想法是将数据存储为字符串,但要记住,如果需要,我们可以转换为Guid(因为身份将由字符串或Guid形成)。

public class MyEntityId : MyIdentity
{
    public MyEntityId(Guid identityValue)
        : base(identityValue)
    {
    }
}

public abstract class MyIdentity
{
    protected readonly bool convertableAsGuid;
    protected readonly string value;

    public string Value { get { return this.value; } }

    public MyIdentity(string identityValue)
    {
        this.value = identityValue;

        Guid guid;
        if(Guid.TryParse(identityValue, out guid)==false)
            this.convertableAsGuid = false;
    }

    public MyIdentity(Guid identityValue)
    {
        this.value = identityValue.ToString();
        this.convertableAsGuid = true;
    }
}

static void Main(string[] args)
{
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid()), "Jon Doe");

    var eventHeaders = new Dictionary<string, object>
    {
        {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName}
    };
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    string dataAsString = Encoding.UTF8.GetString(data);

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value;
    var obj = JsonConvert.DeserializeObject(dataAsString, Type.GetType((string)eventClrTypeName));
    // stepping through the above, a zero initialised GUID string is passed in to MyIdentity constructor
}

正如@hvd友好地评论过,似乎只有一个get属性,如果我添加一个set属性,那么它就可以工作(所以我相信实际上并没有使用构造函数字符串值)。我不想在标识上加上setter的原因是编程设计,它是一个标识,一旦创建就不应该更改。

我可以使用属性上的公共get和protected设置,我尝试了关键字[JsonProperty]并且它有效...但是我不想用这些属性装饰我的域对象 - 是否存在另一种方式?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,那么在反序列化时初始化Guid并且您不想创建setter或使用属性来成功反序列化时会遇到问题。请注意,我通过删除接受MyIdentity参数的构造函数来更改Guid类,因为它没有必要,更改了Guid逻辑的解析,因为它永远不会初始化convertableAsGuid正确的属性并创建了MyEvent类,因为你没有在你的问题上发布它。我还创建了在反序列化期间使用的MyCustomConverter类。以下是课程:

public class MyCustomConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (MyEvent);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        existingValue = new MyEvent(new MyEntityId(jObject["Id"]["Value"].ToString()), jObject["Name"].ToString());

        return existingValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public class MyEvent
{
    public MyEntityId Id { get; set; }

    public string Name { get; set; }

    public MyEvent(MyEntityId id, string name)
    {
        Id = id;
        Name = name;
    }
}

public class MyEntityId : MyIdentity
{
    public MyEntityId(string identityValue)
        : base(identityValue)
    {
    }
}

public abstract class MyIdentity
{
    protected readonly bool convertableAsGuid;
    protected readonly string value;

    public string Value { get { return this.value; } }

    public MyIdentity(string identityValue)
    {
        this.value = identityValue;

        Guid guid;
        if (Guid.TryParse(identityValue, out guid))
            this.convertableAsGuid = true;
    }
}

这是序列化和反序列化逻辑:

static void Main(string[] args)
{
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid().ToString()), "Jon Doe");

    var eventHeaders = new Dictionary<string, object>
        {
            {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName}
        };
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    string dataAsString = Encoding.UTF8.GetString(data);

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value;
    var obj = JsonConvert.DeserializeObject<MyEvent>(dataAsString, new JsonConverter[] {new MyCustomConverter()});
}

演示:https://dotnetfiddle.net/asRtEI