使用generics类型参数代替System.Type类型的参数。 这是一种气味吗?

我经常看到(例如在许多模拟库中)方法,其中使用generics类型参数代替System.Type类型的参数。 我特别谈到generics类型仅用于typeof(T)操作的情况(即,在方法中的任何地方都没有使用类型T的实例,并且T不用于返回类型或其他参数)。

例如,考虑以下方法:

 public string GetTypeName(System.Type type) { return type.FullName; } 

这种方法通常伴随着通用版本:

 public string GetTypeName() { return GetTypeName(typeof(T)); } 

问题是一种不好的做法还是一种好的做法?
这是一种语法糖还是更多呢?

我认为这是滥用语言function来缩写对接受System.Type类型的参数的方法的调用

你觉得这有气味吗? 这应该避免吗? 或者这实际上是一种很好的做法(提供一种通用方法作为避免输入typeof()的快捷方式)。

以下是使用我能想到的这种模式的一些实际问题:

  1. 如果添加了非System.Type类型的参数 – 可能需要将方法重写(如果参数的顺序在语义上很重要)到非generics版本(否则一些参数将是generics类型参数,而一些参数将是常规参数)。
  2. 它需要两个方法(对于在编译时未知类型的情况,通用和非通用)。 因此增加了几乎毫无意义的unit testing。

另一方面,这是一种常见的做法(大多数总是正确的,对吗?)但更重要的是,当我对需要在编译时知道System.Type类型的单个参数的代码进行Extract Method重构时,ReSharper更喜欢该签名(和我学会了接受他们的建议,虽然不是出于信仰,但认真)。

我认为你需要考虑文档。 方法的作用有多明显? 如果您有两个方法(一个使用Type ,另一个使用type参数),则用户需要同时查看并选择。 没有查看代码的人可能没有意识到第二个只是调用第一个代码。

使用两者绝对有意义的是当类型参数实际使用时,它可以是Type版本的某种回退。 例如:

 object GetThingOfType(Type type) { ... } T GetThingOfType() { return (T)GetThingOfType(typeof(T)); } 

另一件需要考虑的事情是:必须始终明确写出类型参数。 如果可能对同一类型对象执行多个操作,则使用类型参数没有帮助。 考虑这样的事情:

 var t = typeof(string); var name = GetTypeName(t); var assemblyName = t.Assembly.FullName; 

即使我知道类型是string ,我也不应该在这里写GetTypeName ,因为我会重复自己。 通过给我一个选项,我通常最好不选择,你增加了一些不必要的复杂性。

更为模糊的一点是IDE支持XML文档。 您记录类型参数,如下所示:

 important information 

然后,如果在C#中键入GetTypeName< ,Visual Studio将显示“T:重要信息”。 但是,由于某种原因,当您键入GetTypeName(Of在Visual Basic中为GetTypeName(Of ,它不会(截至2012年)。

你是对的:考虑方法的语义。 它是在类型的实例上运行还是在类型本身上运行?

如果它在实例上运行,那么它应该是通用方法。 如果它在类型上,则使其成为Type的参数。

所以在你的例子中我会说

 public string GetTypeName(System.Type type) { return type.FullName; } 

 public static int Count(this IEnumerable source) 

正在IEnumerable类型的实例source上运行。

总的来说,我看到仿制药滥用得比使用得多。 执行类型(T)或更糟的类型的任何通用方法实现,使用任何类型的reflection在我看来并不是真正的通用,并且是滥用。 毕竟,generics意味着无论类型参数如何都是一样的,不是吗?

所以,总而言之,我同意你的观点 – 它闻起来很有气味。

我不使用string GetName() { return typeof(T).Name; } 模式,因为它是设计模式的误用(误用可能很强但我想不出正确的词),这是generics的原因,即:generics类型参数适用于编译器和JITter(参见回答这个问题 )这样他们就可以生成特定类型的存储,参数,堆栈变量等。

使用它作为在运行时将类型参数传递给我的方便方法。 有时候typeof(T)是必要的,但我发现它们很少见,而且通常只有在使用generics做复杂的事情时才需要,而不是简单的类型安全类型的东西。 如果我看到了,我肯定会停下来问问自己为什么会这样。

正如已经说过的那样,它在我看来就像个人偏好一样。 根据我的经验,接受类型Type的参数的大多数方法可以使用伴随的扩展方法在语法上“甜化”。

所以,在你的例子中,我会将第二种方法作为扩展。 使用这种方法,您可以获得第二个问题的解决方案 – 不需要进行不必要的unit testing。 然而,第一个仍然存在; 但是,添加参数无论如何都需要重构,因此它将提供更改扩展方法的使用者的机会,以便他们使用原始版本的修改版本。

当然,这只是个人意见。

generics方法优于具有类型Type参数的方法,因为它可以使用提供的类型来处理其他常规事物。 这在以下场景中特别有用:

 public string GetTypeName() { return Cache.TypeName; } private static class Cache { public static readonly TypeName = GetTypeName(typeof(T)); } 

这个缓存很简单,不需要乱用字典,它自动是线程安全的。

这就是说,如果实施不使用这种可能性,那么两者之间的区别仅仅是装饰性的。

处理类型的方法通常只是这样:处理类型。

IMO, Class.Method();Class.Method(typeof(SomeType));要好得多Class.Method(typeof(SomeType));

但我认为这是一个意见问题。

考虑LINQ的.OfType() ,例如:

 personlist.OfType().Where(x => x.EmployeeStatus == "Active"); 

与:

 personlist.OfType(typeof(Employee)).Where(x => ((Employee)x).EmployeeStatus == "Active"); 

你更喜欢哪一个?