英文:
Serialize property access exception to json
问题
我有一个简单的类,其中一个属性是:
public TValue Value => IsSuccess
? _value
: throw new InvalidOperationException("无法访问失败结果的值。");
所以它的工作原理是,当某个操作成功时,将该操作的值分配给属性。但是现在,当我这样做时:
var result = new Result(someValue) { IsSuccess = false };
var serialized = JsonConvert.SerializeObject(result); // 当然,结果类型标记为可序列化
所以在这里,我将这样的结果设置为 false,然后我想将其序列化,问题是异常没有被序列化,我只得到了抛出的异常。我在这里漏掉了什么?
英文:
I have a simple class that one of properties is:
public TValue Value => IsSuccess
? _value
: throw new InvalidOperationException("The value of a failure result can not be accessed.");
So it works like this, when some operation is a success assign value from this operation to property easy. But now I when I do sutch a thig:
var result = new Result (someValue) { IsSuccess = false }
var serialized = JsonConvert.SerializeObject(result); // of course result type is marked as seriazable
So here I am setting such a result to false, and next I want to serilize it, problem is that exception is not serializing and I am getting just thrown exception. What am I missing here?
答案1
得分: 2
我在思考是否有更好的设计来实现你的目标。具体来说,将 IsSuccess
检查逻辑移到一个方法中可能会更好,这样在序列化过程中就不会受到影响。但如果你决定按照这种方式处理,你可以使用 JsonConverter
来捕获和序列化异常,示例代码如下:
public class ValueOrExceptionConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
return;
}
try
{
serializer.Serialize(writer, ((dynamic)value).Value);
}
catch (Exception ex)
{
serializer.Serialize(writer, new { Value = new { ex.Message } });
}
}
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType) => true;
}
我假设你的 Result
类是泛型的,使用这个转换器的方式如下:
[JsonConverter(typeof(ValueOrExceptionConverter))]
public class Result<TValue>
这一切都是基于你使用的是 Newtonsoft.Json。使用该转换器的结果类似于:
{"Value":"Message":"The value of a failure result can not be accessed."}}
有关转换器代码的一些注意事项:
- 你可以考虑使用接口或抽象类,而不是进行动态类型转换,如果你有的话。或者,如果你知道可能用于
TValue
的确切泛型类型,那么你可以进行更具体的类型转换。 - 我假设你不想序列化整个异常。因此,如果你需要的不仅仅是
Message
,还可以添加其他属性,例如:new { ex.Message, InnerMessage = ex.InnerException.Message }
。 - 我假设
Result
类只有一个名为Value
的属性。你可以以相同的方式添加更多属性,就像你可以添加其他异常属性一样。 - 我没有实现
ReadJson
方法,因为反序列化异常而不是值会使事情变得相当复杂。但如果你需要反序列化Result
,我相信这并不是不可能的。
英文:
I'm wondering whether there isn't a better design for what you're trying to achieve. Namely, it might be better to move the IsSuccess
check logic into a method so that it doesn't get hit during serialization. But if you really decide to do it this way, you could use a JsonConverter
to catch and serialize the exception for you:
public class ValueOrExceptionConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
return;
}
try
{
serializer.Serialize(writer, ((dynamic)value).Value);
}
catch (Exception ex)
{
serializer.Serialize(writer, new { Value = new { ex.Message } });
}
}
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType) => true;
}
I'm assuming your Result
class is generic so using this converter would look like this:
[JsonConverter(typeof(ValueOrExceptionConverter))]
public class Result<TValue>
This is all assuming that you're using Newtonsoft.Json. The result of using that converter is something like this:
{"Value":"Message":"The value of a failure result can not be accessed."}}
A few notes about the converter code:
- Instead of casting to
dynamic
, you might be better of using an interface or abstract class if you have it. Or if you know exactly which generics you might use forTValue
then perhaps you can cast even more specifically. - I've assumed that you don't want to serialize the entire exception. So if you need more than just the
Message
then you can add those properties like so for example:new { ex.Message, InnerMessage = ex.InnerException.Message }
. - I've assumed that the
Result
class only has one property, namedValue
. You can add more properties in the same way you can add additional Exception properties. - I haven't implemented the
ReadJson
because deserializing the exception instead of the value makes that quite tricky. But I'm sure it's not impossible if you need to also deserialize theResult
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论