【问题标题】:Is FunctionA(Exception ex) the same as FunctionB<T>(T ex) where T : Exception?Function(Exception ex) 是否与 Function<R>(T ex) where T : Exception 相同?
【发布时间】:2009-04-07 19:36:15
【问题描述】:

关于泛型的两个简单问题。

以下两个函数定义是否相同?

FunctionA(Exception ex);

FunctionB<T>(T ex) where T : Exception;

通用实现 (FunctionB) 与普通实现 (FunctionA) 相比有什么优势吗?

【问题讨论】:

    标签: c# generics


    【解决方案1】:
    【解决方案2】:

    在函数内部,没有区别。差异来自外部。如果您使用泛型函数,您可以将相同类型的异常返回给调用代码,而不是基本的Exception。但在大多数情况下,这是一个有争议的问题。

    【讨论】:

    • 返回类型的问题,以及在实现本身中创建通用对象。此外,如果通用约束包含一个“new()”,那么也用于创建 T 的新实例。但是,在大多数情况下,它没有实际意义是对的。
    • 鉴于他的两个定义,方法内部没有区别。除了属于异常类型之外,它不能做出任何其他假设。但这并不能阻止它返回泛型类型。
    【解决方案3】:

    以下内容实际上是相同的(结果):

    catch (Exception e)
    {
        FunctionA(e);
        FunctionB(e);
    }
    

    但如果你这样做就不一样了:

    catch (ApplicationException e)
    {
        FunctionB(e);
    }
    catch (Exception e)
    {
        FunctionA(e);
    }
    

    这是因为 FunctionB 在编译时被输入到 ApplicationException,而对 FunctionA 的调用总是将参数向下转换为 Exception。根据您对 FunctionB 的实现,这可能无关紧要,但在某些情况下它可以有所作为。我想说的是,根据经验,如果您的方法实现不需要泛型实现,请不要使用它。

    以下是一些重要的例子:

    public T AddSomeContextToThisException<T>(T ex) where T : Exception
    {
        ex.Data.Add("Some key", "Some context message");
        return ex;
    }
    
    public T ThisIsABadIdeaForExceptionsButMaybeAGoodIdeaForOtherTypes<T>(T ex) where T : Exception, new()
    {
        // do something with ex
    
        return new T();
    }
    

    下面的例子需要一些额外的上下文代码,所以请看下面的代码:

    private readonly Bar bar = new Bar();
    
    public void HandExceptionOffToSomethingThatNeedsToBeStronglyTyped<T>(T ex) where T : Exception
    {
        ICollection<T> exceptions = bar.GetCollectionOfExceptions<T>();
        exceptions.Add(ex);
    
        // do other stuff
    }
    
    public class Bar
    {
        // value is object, because .net doesn't have covariance yet
        private Dictionary<Type, object> listsOfExceptions = new Dictionary<Type, object>();
    
        public ICollection<T> GetCollectionOfExceptions<T>()
        {
            if (!listsOfExceptions.ContainsKey(typeof(T)))
            {
                listsOfExceptions.Add(typeof(T), new List<T>());
            }
            return listsOfExceptions[typeof(T)] as List<T>;
        }
    }
    

    【讨论】:

    • 如果 ApplicationException 是 Exception 的子类,那它们不还是一样吗?我理解的 Try/Catch 块;但是,我更关心两者之间是否有任何差异或好处。
    • 如果您在实施中看不到任何好处,那么就没有任何好处,而且差别很小。在某些重要的情况下,请参阅@Samuel 的回答和我对此的评论。
    • 我现在明白了。谢谢。
    【解决方案4】:

    FunctionB 与 FunctionA 相比没有太多优势。但是,两者之间有明显的区别。

    使用 FunctionA,您可以将派生自(或属于)异常的任何类型传递给函数。

    使用 FunctionB,您可以将派生自 T 的任何类型(必须派生自或是异常)传递给函数。

    这意味着根据 T 的类型,您将拥有一个更专业的参数,该参数将限制您可以传递给它的类型,因为该参数将被键入为 T,而不是 Exception。

    现在如果 T 是一个异常,那么没关系,功能是一样的。但是,如果 T 是 InvalidOperationException,则只允许 InvalidOperationException 的实例(以及从它派生的类)。

    这通常是您想要确保类型的特化而不必求助于不提供所需特化级别的基类时所需要的。

    【讨论】:

      猜你喜欢
      • 2013-08-12
      • 2010-12-24
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 2023-03-29
      相关资源
      最近更新 更多