首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用JSON.NET的自定义异常覆盖消息

使用JSON.NET的自定义异常覆盖消息
EN

Stack Overflow用户
提问于 2016-10-11 18:23:35
回答 1查看 668关注 0票数 2

如果您创建了一个自定义异常,它将重写虚拟属性Message,如下所示:

代码语言:javascript
复制
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属性并使其仍然工作?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-11 19:41:24

这是正确的,因为Exception实现了ISerializable和Json.NET 支持此接口。。具体来说,在引用源中,在方法Exception.GetObjectData(SerializationInfo info, StreamingContext context)中,Exception类型序列化基础字段,而不是属性:

代码语言:javascript
复制
        info.AddValue("Message", _message, typeof(String));

如果未设置基础字段,Microsoft可能会这样做,因为Message属性具有默认值:

代码语言:javascript
复制
    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()方法,那么您需要用一些代码气味来做一些事情:

代码语言:javascript
复制
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类型,使其具有可以指定消息的受保护构造函数:

代码语言:javascript
复制
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中覆盖的消息用于调试(例如,因为您正在记录异常),可以将其添加到序列化流中,如下所示:

代码语言:javascript
复制
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);
    }
}

这两种解决方案都避免了代码的气味。

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

https://stackoverflow.com/questions/39984110

复制
相关文章

相似问题

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