如果您创建了一个自定义异常,它将重写虚拟属性Message,如下所示:
public class GrossException : Exception
{
public GrossException() : base("Eww, gross") { }
}
public class BarfException : GrossException
{
public override string Message { get; } = "BARF!!";
}然后,当使用BarfException通过ASP.NET发送JSON.NET时,Message属性将包含
“恶心,恶心”
而不是重写的值。我认为这与异常实现ISerializable有关,但是由于Message属性是虚拟的,难道不应该允许我这样覆盖它并让它工作吗?
是否有适当的方法来实现异常并能够覆盖Message属性并使其仍然工作?
发布于 2016-10-11 19:41:24
这是正确的,因为Exception实现了ISerializable和Json.NET 支持此接口。。具体来说,在引用源中,在方法Exception.GetObjectData(SerializationInfo info, StreamingContext context)中,Exception类型序列化基础字段,而不是属性:
info.AddValue("Message", _message, typeof(String));如果未设置基础字段,Microsoft可能会这样做,因为Message属性具有默认值:
public virtual String Message {
get {
if (_message == null) {
if (_className==null) {
_className = GetClassName();
}
return Environment.GetResourceString("Exception_WasThrown", _className);
} else {
return _message;
}
}
}通过序列化字段而不是属性,默认消息的异常将在反序列化时自动显示在接收系统的CurrentUICulture中。
因此,如果希望消息属性的值出现在JSON中,而不是底层字段中,则需要重写GetObjectData()。而且,由于AddValue()抛出了一个异常,如果您试图添加一个与先前存在的值同名的值,而SerializationInfo没有替换当前值的SetValue()方法,那么您需要用一些代码气味来做一些事情:
public class GrossException : Exception
{
public GrossException() : base("Eww, gross") { }
protected GrossException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class BarfException : GrossException
{
public BarfException() : base() { }
protected BarfException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public override string Message { get { return "BARF!!"; } }
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
var tempInfo = new SerializationInfo(GetType(), new FormatterConverter());
base.GetObjectData(tempInfo, context);
foreach (SerializationEntry entry in tempInfo)
{
if (entry.Name != "Message")
{
info.AddValue(entry.Name, entry.Value, entry.ObjectType);
}
}
info.AddValue("Message", Message);
}
}如您所见,此解决方案违反了继承层次结构的设计,因为基础_message字段的值不再是基类GrossException所需的值。但至少JSON很漂亮。
更好的解决方案是修改GrossException类型,使其具有可以指定消息的受保护构造函数:
public class GrossException : Exception
{
public GrossException() : base("Eww, gross") { }
protected GrossException(SerializationInfo info, StreamingContext context) : base(info, context) { }
protected GrossException(string message) : base(message) { }
}或者,如果您只想看到JSON中覆盖的消息用于调试(例如,因为您正在记录异常),可以将其添加到序列化流中,如下所示:
public class BarfException : GrossException
{
public BarfException() : base() { }
protected BarfException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public override string Message { get { return "BARF!!"; } }
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("OverriddenMessage", Message);
}
}这两种解决方案都避免了代码的气味。
https://stackoverflow.com/questions/39984110
复制相似问题