什么是仿制药滥用?


35

在查看一些代码时,我注意到有机会将其更改为使用泛型。(混淆的)代码如下所示:

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

该代码可以用泛型代替,如下所示:

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

在研究这种方法的优点和缺点时,我发现了一个称为泛滥的术语。看到:

我的问题分为两个部分:

  1. 转向这样的泛型有什么好处?(性能?可读性?)
  2. 什么是泛型滥用?并通过一个通用的有一个类型参数的每一次滥用

2
我糊涂了。您事先知道属性的名称,但不知道对象的类型,因此您使用反射来获取值?
MetaFight

3
@MetaFight我知道这是一个令人费解的例子,实际的代码会很长而且很难放在这里。无论如何,我的问题的目的是确定用泛型替换Type参数是好是坏。
SyntaxRules

12
我一直认为这是泛型存在的典型原因(不是故意的双关语)。当您可以利用类型系统为您自己进行欺骗时,为什么还要自己输入欺骗?
MetaFight

2
您的示例很奇怪,但是我觉得这正是很多IoD库所做的工作
Ewan

14
这不是一个答案,但是值得注意的是第二个示例的灵活性不如第一个示例。将函数设为通用会删除您传递运行时类型的能力;泛型需要在编译时知道类型。
KChaloux

Answers:


87

适当地应用泛型后,它们将删除代码,而不仅仅是重新排列代码。首先,泛型最擅长删除的代码是类型转换,反射和动态类型化。因此,与非泛型实现相比,泛型滥用可以粗略地定义为创建泛型代码,而不会显着减少类型转换,反射或动态类型。

关于您的示例,我希望适当使用泛型将更object[]改为T[]或类似名称,并避免使用Typetype完全使用。这可能需要在其他地方进行大量重构,但是如果在这种情况下使用泛型是合适的,那么在完成后它最终应该会更简单。


3
很好。我承认让我想到的代码正在执行一些难以理解的反思。我看看是否可以更改object[]T[]
SyntaxRules

3
我喜欢移除vs.重新排列特征。
Copper.hat

13
您错过了泛型的一项主要用途-这是减少重复。(尽管您可以通过介绍您提到的任何其他罪行来减少重复)。如果在不删除任何类型转换,反射或动态键入IMO的情况下减少重复,则可以。
Michael Anderson

4
极好的答案。我要补充一点,在这种特殊情况下,OP可能需要切换到接口而不是泛型。看起来好像反射被用来访问对象的特定属性。接口更适合于允许编译器确定此类属性确实存在。
jpmc26

4
@MichaelAnderson“删除代码而不仅仅是重新排列代码”包括减少重复
Caleth

5

我会使用废话规则:与其他所有编程构造一样,泛型也可以解决问题。如果没有问题可以解决泛型,那么使用泛型就是滥用。

在泛型的特定情况下,它们的存在主要是为了抽象出具体的类型,从而允许将不同类型的代码实现折叠到一个泛型模板中(或您的语言碰巧使用的任何形式)。现在,假设您有使用type的代码Foo。您可以将其替换为通用类型T,但是如果您只需要使用该代码Foo,就没有其他代码可以将其折叠在一起。因此,不存在要解决的问题,因此间接添加泛型将仅用于降低可读性。

因此,我建议您仅在不使用泛型的情况下编写代码,直到您需要引入它们为止(因为需要第二个实例化)。然后,只有到那时,才是重构代码以使用泛型的时候了。在我看来,在此之前的任何使用都是虐待。


这听起来似乎有点过于古怪,所以让我提醒您:
编程中没有例外。此规则包括在内。


有趣的想法。但是,稍微改写您的标准可能会有所帮助。假设OP需要一个新的“组件”,该组件将一个int映射到一个字符串,反之亦然。很明显,它解决了一个共同的需求,并且如果将其通用化,将来很容易重用。这种情况属于您对仿制药滥用的定义。但是,一旦确定了非常通用的基本需求,不值得在设计上投入微不足道的额外努力而又不致滥用吗?
Christophe

@Christophe这确实是一个棘手的问题。是的,在某些情况下,确实最好忽略我的规则(在编程中没有规则没有例外!)。但是,实际上涉及特定的字符串转换情况:1.您需要分别处理有符号和无符号整数类型。2.您需要将浮点转换与整数转换分开对待。3.您可以将实现重用为较小类型的最大可用整数类型。您可能希望主动编写一个通用包装来进行转换,但是核心将是没有通用的。
cmaster

1
我反对以可能的YAGNI主动编写泛型(使用前而不是重复使用)。在需要时进行重构。
Neil_UK

在写这个问题时,我采取了更多的立场“尽可能将其写成通用名称,以节省将来可能的重用。” 我知道那有点极端。很高兴在这里看到您的观点。谢谢!
SyntaxRules18年


0

在我看来,您在这里的路正确,但没有完成工作。

您是否考虑过将object[]参数更改Func<T,object>[]为下一步?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.