Исключение сериализации должно быть бросаемым - PullRequest
8 голосов
/ 31 августа 2010

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

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

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

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

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

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

С MSDN:

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

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

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

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

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


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

Ответы [ 2 ]

2 голосов
/ 31 августа 2010

Вы можете создать класс, полученный из 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
    }
}
0 голосов
/ 25 октября 2010

Рассмотрим два класса.

Первым будет сериализуемый класс ExceptionDescription, который должен реализовывать атрибуты, которые вы хотите сериализовать, и наследовать из ничего. Вторым является 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...