Як зловити всі варіанти загального винятку в C #


22

Мені хотілося б спіймати всі варіанти загального винятку класу винятків, і мені було цікаво, чи є спосіб зробити це без безлічі блоків вилову. Наприклад, скажіть, що у мене клас виключень:

public class MyException<T> : Exception
{
    public string MyProperty { get; }

    public MyException(T prop) : base(prop.ToString())
    {
        MyProperty = prop?.ToString();
    }
}

і два похідні класи:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

чи існує спосіб лову MyDerivedStringExceptionі MyDerivedIntExceptionв одному блоці улову.

Я спробував це:

try
{
   ...
}

catch(Exception e) when (e is MyDerivedStringException || e is MyDerivedIntException)
{
}

але це не дуже чисто і означає, що я не маю доступу до нього MyProperty.

Мене цікавить загальне рішення проблеми, але в моєму випадку загальний виняток визначений у бібліотеці третьої сторони, що, як зазначено нижче, додає деякі додаткові обмеження для проблеми.

Відповіді:


15

Складіть MyException<T>реалізацію інтерфейсу та перевірте виняток за типом інтерфейсу.

Інтерфейс:

public interface IMyException
{
    string MyProperty { get; }
}

Загальний клас, що реалізує інтерфейс:

public class MyException<T> : Exception, IMyException
{
    public string MyProperty { get; }

    public MyException(T prop)
    {
        MyProperty = prop?.ToString();
    }
}

Отримані заняття:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

Використання:

try
{
    // ...
}
catch (Exception e) when (e is IMyException)
{
    // ...
}

Те ж саме можна зробити, створивши базовий клас, який успадковує Exceptionта MyException<T>отримує походження від цього базового класу.


3
Я не впевнений, що тут варто використовувати інтерфейс - просто негенеральний базовий клас між, Exceptionі MyException<T>було б добре.
Джон Скіт

Крім того, ОП досі не має доступу до загальної властивості (без використання рефлексії), що, напевно, є справжньою проблемою.
DavidG

10

Тест, якщо ваш Typeпоходить із загального, є:

Type = typeof(something);
t.GetGenericTypeDefinition()==typeof(MyException<>);

Але це справедливо лише для самих похідних типів, як-от MyException<int>або MyException<string>.

Якщо у вас є інші похідні, як MyDerivedStringExceptionвам довелося тестувати:

ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>);

Таким чином, це працює для будь-яких існуючих загальних, але вам потрібно знати рівень успадкованості для цього тесту, або провести цикл через усі базові типи.

Отже, ви могли це зробити:

catch(Exception ex) when (ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>))

3

Це поле для введення та вимкнення, якщо T: Value - це Valuetype ..., але щодо використання ви можете контролювати наслідки щодо продуктивності, скільки разів ви намагаєтесь встановити / відключити.

public class MyException<T> : MyException
{
    public T Prop => (T)base.Prop;

    public MyException(T prop) : base(prop)
    {

    }
}

public class MyException : Exception
{
    protected object Prop { get; }

    public MyException(object prop)
    {
         Prop = prop;
    }
}

Логіка

try {
     ...
} catch(MyException e) {
    ...
}

Це хороша відповідь, і я підтримав - на жаль, це не вирішує мою конкретну проблему, оскільки загальний виняток є у бібліотеці третьої сторони, тому я не можу редагувати її.
SBFrancies

2

На жаль, ви не можете наздогнати

catch(MyException ex) клас, як він очікує типу.

Вашою найкращою ставкою буде створення базового класу чи інтерфейсу, спіймання та отримання типу звідти.

Тут уже є відповідь на те, як отримати тип і зробити це.


1

ця реалізація абстрагує делегата обробку для типу винятку далеко від контексту T / C ... Це може бути занадто авантюрним, але прохолодна частина цього - ви можете вводити різні обробники залежно від сфери повторного використання та контексту утилізація.

public interface IExceptionHandler
{
    object Handle(Exception ex);

    void RegisterExceptionTypeHandler<T>(Func<T,object> handlerDelegate) where T : Exception;
}

логіка реєстрації

handler.RegisterExceptionTypeHandler<MyException<int>>(ex => ...);
handler.RegisterExceptionTypeHandler<MyException<string>>(ex => ...);

try {
    ...
}catch(Exception ex)
{
    ...any validation
    return exceptionHandler.Handle(ex)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.