Newtonsoft.Json 的 DeserializeObject 方法如何处理传入值为 00000000-0000-0000-0000-000000000000 的 GUID 参数?

3
我有一个用于表示身份的类,其中包含一个字符串值。我还有另一个用于表示事件的类,其中包括一个身份对象和一个字符串名称。
我可以将对象从对象序列化为JSON字符串,但是当我将上述JSON转换为对象时,在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和受保护的set属性,我尝试了关键字[JsonProperty],它可以工作......但是我不想用这些属性装饰我的领域对象 - 还有其他方法吗?

2
问题可能是Value属性没有setter,无法映射到构造函数参数,但这并不能真正帮助你解决它。 - user743382
1
就我个人而言,在我的情况下,我使用受保护的属性设置器时会出现每个GUID都变成空GUID的行为。这就是我提出这个问题的原因。最终,我不得不将其转换为完全公共的属性,从架构的角度来看,我也不喜欢这种方式,但实际上,在我特定的情况下并不太糟糕。 - Bernard Hymmen
1个回答

1
如果我理解正确,您在反序列化时遇到了初始化Guid的问题,并且您不想创建setter或使用属性来实现成功的反序列化。请注意,我通过删除接受Guid参数的构造函数来更改了您的MyIdentity类,因为这是不必要的,更改了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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接