将异常类型列表作为类型参数传递给泛型方法

时间:2015-12-12 20:48:20

标签: c# generics exception-handling

我正在尝试编写一个通用的辅助方法,它可以调用方法并处理异常(如果有的话)。

该方法应该能够接受List个可接受的Exception类型,并以特定方式处理它们。对于其他类型的异常,它将以不同的方式处理。

这是方法的简化版本

public static TResult InvokeMethod<TResult, TAllowedException>
                (Func<TResult> func) where TAllowedException : Exception
{
    try
    {
        return func();
    }
    catch (Exception ex)
    {
        if (ex is TAllowedException) //do something
            return default(TResult);
        else //do something else
            throw;
    }
}

此处我将允许的例外类型指定为TAllowedException。这很好用。但是,这只接受一个Exception_Type。我怎样才能传递List<Exception_Type>

1 个答案:

答案 0 :(得分:4)

您不能将类型列表作为类型参数传递给泛型方法。

为什么不简单地将一组类型作为常规参数传递?

public static TResult InvokeMethod<TResult>
        (Func<TResult> func, ICollection<Type> ignoredExceptions)
{
    try
    {
        return func();
    }
    catch (Exception ex)                         
        when (ignoredExceptions != null &&                    
              ignoredExceptions.Any(t => t.IsAssignableFrom(ex.GetType())))
    {
        return default(TResult);
    }
}

如果有人通过了Type这不是一个例外,那么一切都不会发生。在我看来,没有必要验证它。该方法仍然可以正常工作 - 集合中的异常将被忽略。

调用InvokeMethod(func, new Type[] { typeof(Int32) })的预期行为是什么? func将被执行,如果它抛出Int32的异常,将返回默认结果。 func永远不会抛出Int32个异常,因此在没有验证ignoredExceptions的情况下它已经正常运行。

BTW传递arg作为参数不是必需的。您可以使用lambda在闭包中捕获arg - () => func(arg)。这将适用于任何数量的论点。

修改

如果你真的想在编译时限制类型,你必须创建自己的集合,有一点奇怪的通用Add方法:

public class ExceptionCollection : IEnumerable<Type>
{
    private readonly List<Type> _exceptions = new List<Type>();        

    public void Add<T>() where T : Exception => _exceptions.Add(typeof(T));
    public IEnumerator<Type> GetEnumerator() => _exceptions.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_exceptions).GetEnumerator();
}

这个类的最大缺点是它不适用于集合初始化器。

有一种方法可以使它与集合初始化器一起使用。初始化程序需要使用Add方法获取一个参数,但他们会很乐意使用通用的Add<T>(T item)方法。

public void Add<T>(T item) where T : Exception => _exceptions.Add(typeof(T));

使用它也有点棘手。我们当然可以传递异常实例,但创建实例只是为了获取它的类型是没有意义的。我们可以使用强制类型null来传递强制类型default(T)或使用new ExceptionCollection { default(ArgumentNullException), default(ArgumentException) };

ALTER TABLE book ADD FULLTEXT(name);

我仍然认为在这种特殊情况下,没有必要验证类型集合。可能还有其他情况需要约束的类型集合 - 然后上面的解决方案就可以了。