如何在C#中捕获通用异常的所有变体


22

我想捕获一个通用异常类的所有变体,我想知道是否有一种方法可以在没有多个catch块的情况下进行。例如说我有一个异常类:

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)
    {

    }
}

有没有一种方法可以同时捕获MyDerivedStringExceptionMyDerivedIntException捕获一个捕获块。

我已经试过了:

try
{
   ...
}

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

但是它不是很干净,意味着我无法使用MyProperty

我对问题的一般解决方案感兴趣,但是在我的情况下,通用异常是在第三方库中定义的,如下所述,该库为问题增加了一些其他约束。

Answers:


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>会被罚款。
乔恩·斯基特

另外,OP仍然无法访问泛型属性(不使用反射),我想这是真正的问题。
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)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.