繁体   English   中英

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

[英]How to catch all variants of a generic exception in C#

我想捕获一个通用异常类的所有变体,并且我想知道是否有一种方法可以在没有多个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)
    {

    }
}

有没有一种方法可以在一个catch块中同时捕获MyDerivedStringExceptionMyDerivedIntException

我已经试过了:

try
{
   ...
}

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

但是它不是很干净,意味着我无法访问MyProperty

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

使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>从该基类派生,可以做到这一点。

如果您的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<>))

如果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) {
    ...
}

不幸的是,您无法赶上

catch(MyException ex)类,因为它需要一个类型。

最好的选择是创建一个基类或接口,捕获它并从中获取类型。

已经有上回答所以这里就如何获得类型和做到这一点。

该实现将异常类型的处理委托从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)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM