Сериализация исключения для throwable

хотя я понимаю, что есть подобный вопрос (как сериализовать объект исключения в C#?), и хотя ответы на этой странице были полезны, они не совсем решили проблему или ответили на поставленный вопрос.

я считаю, что вопрос состоял в том, как сериализовать объект, чтобы позволить ему быть реконструированным (десериализованным) в тот же объект. Я попытался использовать решение, данное davogones и Энтони Бут, но без добавления System.Exception базовый класс, на стороне потребления (как в: SerializationException: Exception), невозможно использовать эти типы (сами по себе) в качестве фактических объектов исключения, которые могут быть брошены.

прежде чем я продолжу, позвольте мне объяснить, что последнее заявление. Я пытался использовать решение Антония Бута в веб-службе (служба содержит определение для сериализуемого объекта) в попытке заставить всех потребителей использовать одно и то же исключение (надеюсь, создание многоразового сериализуемый тип исключения вместо того, чтобы воссоздавать его повсюду).

к сожалению, поскольку ни один из типов явно не является производным от System.Exception нельзя throw их, что, очевидно, было бы полезно. Как я уже упоминал выше, кажется, что добавление : Exception к определению класса типа на стороне потребления позволяет объекту быть брошенным, но это требует редактирования автоматически сгенерированного кода WSDL / веб-службы, который интуитивно кажется мне плохой / не поддерживаемой практикой (правильно я, если я ошибаюсь).

мой первый вопрос, опять же, можно ли сериализовать System.Exception или создать производный тип, который может быть сериализован, и если это возможно,как это сделать? Я должен упомянуть, что я посмотрел на то, что кажется официальным способом восстановить Exception объект

мой второй вопрос касается архитектуры . Что я хотел бы знать, почему the System.Exception тип помечен как [Serializable] когда он был задокументирован и, по-видимому, разработан, чтобы запретить вам сериализацию его должным образом (по крайней мере, с XML), потому что это Data объект IDictionary?

С MSDN:

Q: почему я не могу сериализовать хэш-таблицы?

A: XmlSerializer не может обрабатывать классы, реализующие интерфейс IDictionary. Отчасти это было связано с графиком ограничения и частично из-за того, что хэш-таблица не имеет аналога в системе типа XSD. Единственное решение-реализовать пользовательскую хэш-таблицу, которая не реализует интерфейс IDictionary.

учитывая, что XML становится (если еще не является) новым стандартом для транспортировки данных (официально рекомендованным Microsoft, тем не менее), кажется абсурдно глупым не разрешать единственный тип объекта в .NET, который может быть брошен, чтобы не быть В XML-сериализацию.

я с нетерпением жду услышать некоторые мысли от всех SO'RS (тем более, что это мой первый пост).

если у вас есть вопросы или нужны разъяснения, пожалуйста, не стесняйтесь дайте мне знать.


примечание: Я только что нашел это так пост, что, кажется, отвечает на несколько вопросов, но я думаю, что я хотел бы получить свой собственный удар. дайте мне знать, если это слишком близко к дубликату.

2 ответов


можно создать класс, производный от Exception и выполните сериализацию и десериализацию самостоятельно, реализовав ISerializable интерфейс.

пример взят из издательства wrox форумов, подклассы ApplicationException:

редактировать: так как указано, ApplicationException устарела. Использование базы Exception класс должен работать нормально.

using System;
using System.Collections;
using System.Runtime.Serialization;

namespace Common.CustomExceptions
{

    /// <summary>
    /// Custom exception.
    /// </summary>
    [Serializable]
    public class CustomExceptionBase: ApplicationException
        {

        // Local private members
        protected DateTime _dateTime = DateTime.Now;
        protected String _machineName = Environment.MachineName;
        protected String _exceptionType = "";
        private String _exceptionDescription = "";
        protected String _stackTrace = "";
        protected String _assemblyName = "";
        protected String _messageName = "";
        protected String _messageId = "";
        protected Hashtable _data = null;
        protected String _source = "";
        protected Int32 _exceptionNumber = 0;

        public CustomExceptionBase(): base()
        {
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber): base()
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message): base(message)
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException, String messageName, String mqMessageId): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            this._messageId = mqMessageId;
            this._messageName = messageName;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException, String messageName, String mqMessageId, String source): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            this._messageId = mqMessageId;
            this._messageName = messageName;
            this._source = source.Equals("") ? this._source : source;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }


        #region ISerializable members

        /// <summary>
        /// This CTor allows exceptions to be marhalled accross remoting boundaries
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected CustomExceptionBase(SerializationInfo info, StreamingContext context) :
            base(info,context)
        {
            this._dateTime = info.GetDateTime("_dateTime");
            this._machineName = info.GetString("_machineName");
            this._stackTrace = info.GetString("_stackTrace");
            this._exceptionType = info.GetString("_exceptionType");
            this._assemblyName = info.GetString("_assemblyName");
            this._messageName = info.GetString("_messageName");
            this._messageId = info.GetString("_messageId");
            this._exceptionDescription = info.GetString("_exceptionDescription");
            this._data = (Hashtable)info.GetValue("_data", Type.GetType("System.Collections.Hashtable"));
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_dateTime", this._dateTime);
            info.AddValue("_machineName", this._machineName);
            info.AddValue("_stackTrace", this._stackTrace);
            info.AddValue("_exceptionType", this._exceptionType);
            info.AddValue("_assemblyName", this._assemblyName);
            info.AddValue("_messageName", this._messageName);
            info.AddValue("_messageId", this._messageId);
            info.AddValue("_exceptionDescription", this._exceptionDescription);
            info.AddValue("_data", this._data, Type.GetType("System.Collections.Hashtable"));
            base.GetObjectData (info, context);
        }

        #endregion
    }
}

рассмотреть два класса.

первым будет сериализуемый класс ExceptionDescription, который должен реализовать атрибуты, которые вы хотите сериализовать, и наследуется от nothing. Второй-CustomException, который наследуется от Exception и имеет одну ссылку на экземпляр ExceptionDescription. Кроме того, CustomException реализует "открытый статический неявный оператор", поэтому вы можете естественным образом перемещаться между двумя реализациями.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml.Serialization;

namespace SerializableException {


public class CustomException : Exception {


    public CustomException(ExceptionDescription d) {
        this.description = d;
    }//method


    public CustomException(String message, Exception e) {
        this.description = new ExceptionDescription(message, e, 2);
    }//method

    public CustomException(String message, Exception e, int stackDepth) {
        this.description = new ExceptionDescription(message, e, stackDepth + 1);
    }//method


    public CustomException(String message, IEnumerable<Exception> causes) {
        this.description = new ExceptionDescription(message, causes, 2);
    }//method


    public CustomException(String message, IEnumerable<Exception> causes, int stackDepth) {
        this.description = new ExceptionDescription(message, causes, stackDepth + 1);
    }//method


    public CustomException(String message) {
        this.description = new ExceptionDescription(message, 2);
    }//method


    public CustomException(String message, int stackDepth) {
        this.description = new ExceptionDescription(message, stackDepth + 1);
    }//method


    public CustomException() {
    }//method


    public static CustomException newInstance(Exception e) {
        if (e == null) return null;
        if (e is CustomException) return (CustomException)e;

        CustomException output = new CustomException();
        output.description = ExceptionDescription.newInstance(e);
        return output;
    }//method


    public static implicit operator ExceptionDescription(CustomException e) {
        if (e == null) return null;
        return e.description;
    }//method

    public static implicit operator CustomException(ExceptionDescription d) {
        return d == null ? null : new CustomException(d);
    }//method


    public ExceptionDescription description;



    public String RawStackTrace {
        get { return description.RawStackTrace; }
        //set { rawStackTrace = value; }
    }//method


    public DateTime Time {
        get { return description.Time; }
    }//method

    public override String Message {
        get { return description.Message; }
    }//method


}//class




[XmlRoot]
public class ExceptionDescription {

    public ExceptionDescription() {
    }//method


    public ExceptionDescription(String message, Exception cause, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(1 + stackDepth, true).ToString();
        this.Causes = new ExceptionDescription[] { ExceptionDescription.newInstance(cause) };
    }//method



    public ExceptionDescription(String message, IEnumerable<Exception> causes, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(1 + stackDepth, true).ToString();
        this.Causes = (from Exception e in causes select ExceptionDescription.newInstance(e)).ToArray();
    }//method


    public ExceptionDescription(String message, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(stackDepth + 1, true).ToString();
        this.Causes = new ExceptionDescription[0];
    }//method



    public static ExceptionDescription newInstance(Exception e) {
        if (e == null) return null;
        if (e is CustomException) return ((CustomException)e).description;

        ExceptionDescription output = new ExceptionDescription();
        output.Time = DateTime.Now;
        output.Message = e.Message;
        output.RawStackTrace = e.StackTrace;

        if (e.InnerException != null) {
            output.Causes = new ExceptionDescription[] { ExceptionDescription.newInstance(e.InnerException) };
        } else {
            output.Causes = new ExceptionDescription[0];
        }//endif
        return output;
    }//method





    public String Message;
    public ExceptionDescription[] Causes;       //MORE THAN ONE CAUSE IS LEGITIMATE             
    public String RawStackTrace;
    public DateTime Time;



}//class



}//namespace