隐式泛型类型参数是什么?

12

我发现了Servy的一个回答(https://stackoverflow.com/a/15098242/496680),他的一些代码是这样的:

public static int BinarySearch<TSource, TKey>(...)

这是一个扩展方法,但他的调用方式如下:

arr.BinarySearch(...)

我询问了一些人,有人提到这是一个隐含的通用类型参数。我在谷歌上搜索,但没有找到相关信息。我理解泛型的工作原理,但我不明白如何/何时使用它们。

  1. 为什么Servy在他的扩展方法中使用它们?
  2. 是否有一个更正式的名称,我可以搜索到?

2
我可以简单地回答第一点。这允许该方法适用于任何类型的集合,而不仅仅是字符串、整数、Foos或其他类型。它还允许您与任何类型的值进行比较,无论是int、string、Bar还是[...]等等。在您特定的情况下,您只需要从某种类型的数组中选择一个int。使用泛型,它不仅适用于您的一个案例,而且适用于任何类似的情况,但具有不同的类型。这将对未来找到您问题的访问者更有帮助。 - Servy
@Servy 谢谢!对于未来的读者,我还发现了这篇文章:https://dev59.com/_1PTa4cB1Zd3GeqPoPtC - Steve's a D
3个回答

11
好的,您漏掉了最重要的部分,这使得所有内容都可行。类型参数可以由传入的实际对象参数推断出来。
例如:
static class Extensions {
  internal static IEnumerable<U> Test<T, U>(
                                   this IEnumerable<T> items,
                                   Func<T, U> converter) {
    foreach (T item in items) {
      yield return converter(item);
    }
  }
}

这个扩展方法适用于任何IEnumerable类,根据提供的转换器将枚举中的每个项转换为另一种类型。这是标准泛型。
现在,有许多调用此方法的方式:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");

// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);

// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);

// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);

// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);

所有四种变体都调用相同的方法并返回相同的结果。类型推断通过查看传递的参数并根据所提供的内容自动推断它们的类型来工作。在我们上面的示例中,它能够确定类型Tint类型,因为我们将IEnumerable<int>传递到了IEnumerable<T>参数中。它还能够推断出类型Ustring类型,因为我们传递了一个与T的初始类型匹配的Func并返回一个字符串。因此,Func<T, U>被填充了我们的转换器函数Func<int, string>
从上述推断可以看出,这是一个标准的通用方法。类型推断和扩展方法只不过是方便/语法糖。实际上,如果你反编译输出,你会看到扩展方法被替换为静态调用,并且通常定义了明确填写的类型参数。(这取决于你的反编译器和设置选项)。

对于您最后的两个示例,您需要省略 values 作为参数。 - Servy
哎呀,谢谢!当你无法编译时,你会错过很多东西,这真是太神奇了! - Joshua

6
  1. 在这种情况下,他使用了一个通用方法,因为它允许他的方法与包含在Collection<T>中的任何类型一起使用。 通用方法使其非常灵活,并可用于任何类型。 他在调用方法时使用类型推断,因为它简化了调用现场的代码。

  2. 自动处理称为类型推断,并在C#语言规范第7.5.2节中详细介绍:类型推断。 如果您想详细了解它,我建议下载C#语言规范


2
我通常听到的术语是“类型推断”。

是的,这被称为“类型推断”。在通用方法(C#编程指南)中有一个非常基本的例子,其中写道:“您还可以省略类型参数,编译器将推断它。以下对Swap的调用等同于先前的调用:[...]类型推断的相同规则适用于静态方法和实例方法。编译器可以根据您传递的方法参数推断类型参数;它无法仅从约束或返回值推断类型参数。[...]” - Jeppe Stig Nielsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接