我经常看到(例如在许多模拟库中)方法,其中使用泛型类型参数代替类型System.Type
的参数。我特别谈到泛型类型仅在typeof(T)
操作中使用的情况(即,在方法中的任何地方都没有使用类型T的实例,并且T不用于返回类型或其他参数)。
例如,请考虑以下方法:
public string GetTypeName(System.Type type) { return type.FullName; }
此方法通常附带通用版本:
public string GetTypeName<T>() { return GetTypeName(typeof(T)); }
问题 这是一种不好的做法还是一种好的做法? 这是一种语法糖还是还有更多呢?
我认为这是滥用语言功能来缩短对接受System.Type
类型的参数的方法的调用
typeof()
的快捷方式)。
以下是使用我能想到的这种模式的一些实际问题:
另一方面,这是一种常见的做法(大多数总是正确的,对吧?)但更重要的是,当我对需要单一参数类型System.Type的代码进行Extract Method重构时,ReSharper更喜欢该签名。时间(我学会了接受他们的建议,虽然不是出于信仰,但认真)。
答案 0 :(得分:3)
我认为您需要考虑文档。方法的作用有多明显?如果您有两个方法(一个具有Type
,另一个具有类型参数),则用户需要同时查看并选择。没有查看代码的人可能没有意识到第二个人只是调用第一个代码。
使用两者绝对有意义的是当实际使用类型参数时,Type
版本存在某种后退。例如:
object GetThingOfType(Type type) { ... }
T GetThingOfType<T>() { return (T)GetThingOfType(typeof(T)); }
需要考虑的另一件事:必须始终明确写出类型参数。如果使用相同类型对象可能会执行多个操作,则使用类型参数没有帮助。考虑这样的事情:
var t = typeof(string);
var name = GetTypeName(t);
var assemblyName = t.Assembly.FullName;
即使我知道类型是string
,我也不应该在这里写GetTypeName<string>
,因为我会重复自己。通过给我一个选项,我通常最好不选择,你会增加一些不必要的复杂性。
更为模糊的一点是IDE支持XML文档。您可以像这样记录类型参数:
<typeparam name="T">important information</typeparam>
然后,如果在C#中键入GetTypeName<
,Visual Studio将显示“T:重要信息”。但是,出于某种原因,当您在Visual Basic中键入GetTypeName(Of
时,它不会(截至2012年)。
答案 1 :(得分:3)
你是对的:考虑方法的语义。它是在类型的实例上运行,还是在类型本身上运行?
如果它在实例上运行,那么它应该是通用方法。如果它在类型上,则使其成为Type
类型的参数。
所以在你的例子中我会说
public string GetTypeName(System.Type type) { return type.FullName; }
尽管
public static int Count<TSource>(this IEnumerable<TSource> source)
正在source
类型的实例IEnumerable<TSource>
上运行。
总的来说,我看到仿制药滥用得比使用得多。执行类型(T)或更糟的类型的任何通用方法实现,使用任何类型的反射在我看来并不是真正的通用,并且是滥用。毕竟,泛型意味着无论类型参数如何,它的工作方式都相同,不是吗?
因此,总而言之,我同意你的观点 - 它闻起来。
答案 2 :(得分:1)
我不使用string GetName<T>() { return typeof(T).Name; }
模式,因为它是设计模式的滥用(滥用可能很强但我想不出正确的词),这是泛型的原因,即:generic类型参数适用于编译器和JITter(请参阅this question的答案),以便它们可以生成特定类型的存储,参数,堆栈变量等。
使用它作为在运行时将类型参数传递给我的方便方法。有时typeof(T)
是必要的,但我发现它们很少见,通常只有在使用泛型做复杂的事情时才需要,而不是简单的类型安全类型。如果我看到它,我肯定会停下来问问自己为什么会这样。
答案 3 :(得分:0)
处理类型的方法通常只是这样:处理类型。
IMO,Class.Method<SomeType>();
比Class.Method(typeof(SomeType));
但我认为这是一个意见问题。
考虑LINQ的.OfType<T>()
,例如:
personlist.OfType<Employee>().Where(x => x.EmployeeStatus == "Active");
与
personlist.OfType(typeof(Employee)).Where(x => ((Employee)x).EmployeeStatus == "Active");
你更喜欢哪一个?
答案 4 :(得分:0)
正如人们已经说过的那样,它在我看来就像个人偏好一样。根据我的经验,接受 Type 类型参数的大多数方法都可以使用附带的扩展方法在语法上“加糖”。
所以,在你的例子中,我会将第二个方法作为扩展。使用这种方法,您可以获得第二个问题的解决方案 - 不需要进行不必要的单元测试。然而,第一个仍然存在;但是,添加参数无论如何都需要重构,因此它将提供更改扩展方法的使用者的机会,以便他们使用原始版本的修改版本。
当然,这只是个人意见。
答案 5 :(得分:0)
泛型方法优于具有类型Type
的参数的方法,因为它可以使用提供的类型来处理其他常规事物。这在以下场景中特别有用:
public string GetTypeName<T>()
{
return Cache<T>.TypeName;
}
private static class Cache<T>
{
public static readonly TypeName = GetTypeName(typeof(T));
}
这个缓存很简单,不需要乱用字典,它自动是线程安全的。
这就是说,如果实施不使用这种可能性,那么两者之间的区别只是装饰性的。