【发布时间】:2009-04-07 19:36:15
【问题描述】:
关于泛型的两个简单问题。
以下两个函数定义是否相同?
FunctionA(Exception ex);
FunctionB<T>(T ex) where T : Exception;
通用实现 (FunctionB) 与普通实现 (FunctionA) 相比有什么优势吗?
【问题讨论】:
关于泛型的两个简单问题。
以下两个函数定义是否相同?
FunctionA(Exception ex);
FunctionB<T>(T ex) where T : Exception;
通用实现 (FunctionB) 与普通实现 (FunctionA) 相比有什么优势吗?
【问题讨论】:
在函数内部,没有区别。差异来自外部。如果您使用泛型函数,您可以将相同类型的异常返回给调用代码,而不是基本的Exception。但在大多数情况下,这是一个有争议的问题。
【讨论】:
以下内容实际上是相同的(结果):
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>;
}
}
【讨论】:
FunctionB 与 FunctionA 相比没有太多优势。但是,两者之间有明显的区别。
使用 FunctionA,您可以将派生自(或属于)异常的任何类型传递给函数。
使用 FunctionB,您可以将派生自 T 的任何类型(必须派生自或是异常)传递给函数。
这意味着根据 T 的类型,您将拥有一个更专业的参数,该参数将限制您可以传递给它的类型,因为该参数将被键入为 T,而不是 Exception。
现在如果 T 是一个异常,那么没关系,功能是一样的。但是,如果 T 是 InvalidOperationException,则只允许 InvalidOperationException 的实例(以及从它派生的类)。
这通常是您想要确保类型的特化而不必求助于不提供所需特化级别的基类时所需要的。
【讨论】: