обработка исключений с помощью полиморфизма - PullRequest
2 голосов
/ 14 июня 2011

Мне нужна точка зрения в этой конструкции, которую я предлагаю для обработки исключений.

У меня есть служба wcf, которая генерирует различные типы исключений ошибок:

  1. throw new FaultException (...)
  2. throw new FaultException (...)
  3. ...
  4. ...

Все эти классы исключений ошибок реализуют интерфейс IViolationFault, который имеет единственный метод HandleException,Реализация каждого такого метода различна в зависимости от класса, в котором они находятся;так, например, когда эти классы исключений попадают в клиент, все, что мне нужно сделать, это просто вызвать этот метод HandleException (), и об этом позаботятся, и мне не придется писать условие IF, чтобы различать типы ошибок.В методе HandleException () BusinessRuleViolationFault я мог бы просто захотеть показать сообщение на экране, в то время как в другом я мог бы захотеть зарегистрировать его где-нибудь и вызвать какое-то другое действие ...

catch (FaultException<BusinessRuleViolationFault> ex)
 {
ex.HandleException();
 }
catch (FaultException<SomeOtherViolationFault> ex)
 {
ex.HandleException();
 }

Вопросы

  1. Есть ли что-то неправильное в этом подходе?
  2. Есть ли способ уменьшить количество блоков перехвата и сделать так, чтобы всего один блок перехвата заботился обо всех типах исключений?
  3. Является ли это хорошим объектно-ориентированным способом для достижения полиморфизма при обработке исключений?

EDIT

Я изменил код для наследования от базыкласс вместо реализации интерфейса.Мой класс BusinessRuleViolationFault имеет метод HandleException, но я не могу получить метод HandleException в клиентском блоке перехвата.Что я делаю не так?Вот как его бросают в сервис

BusinessRuleViolationFault bf = new BusinessRuleViolationFault("");
throw new FaultException<BusinessRuleViolationFault>(bf, new FaultReason(new FaultReasonText("Fault reason here")));

Это мой код BusinessRuleViolationFault

[DataContract]
public class BusinessRuleViolationFault : BaseFault
{
    public BusinessRuleViolationFault(string message)
        : base(message)
    {

    }


    [OperationContract]
    public override string HandleException()
    {
        return "BusinessRuleViolationFault executed";
    }
}



[DataContract]
public abstract class BaseFault
{
    public BaseFault(string message)
    {
        Message = message;
    }

    [DataMember]
    public string Message { get; set; }

    [OperationContract]
    public abstract string HandleException();
}

Позвольте мне высказать свои мысли по этому поводу.Спасибо за ваше время ...

Ответы [ 3 ]

1 голос
/ 14 июня 2011

РЕДАКТИРОВАТЬ : исправить пример кода.

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

// Does not work
try
{
}
catch (FaultException<IVoliationFault> ex)
{
  ex.HandleException();
}

перехватить ваши FaultExceptions.

Вы также (очевидно) не можете изменить базовый класс System.ServiceModel.FaultException<TDetail> или даже System.ServiceModel.FaultException включить любой HandleException() метод.

Что вы можете сделать, это работать с отражением, чтобы извлечь TDetail FaultException, если таковой имеется, и затем работать с этим:

        try
        {
        }
        catch (FaultException ex)
        {
            var detail = ex.GetDetail<IViolationFault>(); // EDIT: Specify type

            if (detail != null)
            {
                detail.HandleException();
            }
            else
            {
                // Either not a FaultException<TDetail>, or not FaultException<IViolationFault>.
                throw;
            }
        }
...

public static class FaultExceptionExtensions
{
    public static T GetDetail<T>(this FaultException exception)
    {
        if (exception == null)
            throw new ArgumentNullException("exception");

        Type type = exception.GetType(); // EDIT: use "exception" instead of "ex"
        if (!type.IsGenericType)
        {
            return default(T);
        }

        Type genType = type.GetGenericArguments()[0];

        PropertyInfo pi = type.GetProperty("Detail", genType);
        Debug.Assert(pi != null, "FaultException<" + genType + ">.Detail property is missing");

        object val = pi.GetValue(exception, null);

        if (!typeof(T).IsInstanceOfType(val))
        {
            return default(T);
        }

        return (T)val;
    }

}
0 голосов
/ 14 июня 2011

Возможно, вы захотите взглянуть на функциональный подход, описанный в этом сообщении в блоге , который позволяет вам сделать вашу логику «попробуй / поймать» немного более понятной / краткой. например:

TryCatch.Try(() =>
         {
             using (var stream = File.OpenRead(FileTextBox.Text))
             {
                 Trace.WriteLine(stream.Length);
             }
         })
.Catch<FileNotFoundException,
    DirectoryNotFoundException,
    UnauthorizedAccessException>
    (ex =>
    {
        MessageBox.Show(ex.Message, "Fail");
    });
0 голосов
/ 14 июня 2011

В этом подходе нет ничего плохого, это просто обычное использование полиморфизма.

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

public abstract class FaultException : Exception
{
    public abstract void HandleException()
}

public class Faultexception<T> : FaultException
{
     public override void HandleException()
     {
      //your code here
     }
}

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

catch (FaultException ex) 
{
     ex.HandleException();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...