泛型接口
对类型进行抽象。
泛型接口 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
什么是泛型接口?
泛型接口会在名称后的尖括号中声明类型参数。实现类选择具体类型,接口契约也会相应适配。
.NET 类库处处使用泛型接口,例如 IEnumerable<T> 和 IComparable<T>。
interface IRepository<T>
{
void Add(T item);
T Get(int id);
}实现泛型接口
类可以通过提供具体类型参数来实现泛型接口。方法签名随后会使用该实际类型。
这样可以在无需类型转换的情况下,提供类型安全且可复用的契约。
using System.Collections.Generic;
class IntStore : IRepository<int>
{
private readonly List<int> data = new();
public void Add(int item) => data.Add(item);
public int Get(int id) => data[id];
}
interface IRepository<T>
{
void Add(T item);
T Get(int id);
}让实现类保持泛型
类可以在自身保持为泛型类的同时实现泛型接口,将自己的类型参数传递给该接口。
这样可以让实现适用于任意元素类型。
using System.Collections.Generic;
class Store<T> : IRepository<T>
{
private readonly List<T> data = new();
public void Add(T item) => data.Add(item);
public T Get(int id) => data[id];
}
interface IRepository<T> { void Add(T item); T Get(int id); }实际使用 IComparable<T>
IComparable<T> 是内置的泛型接口。实现它可以让您的类型定义实例的排序方式,从而支持排序。
CompareTo 方法会返回负数、零或正数。
class Money : IComparable<Money>
{
public int Cents;
public int CompareTo(Money? other)
=> Cents.CompareTo(other?.Cents ?? 0);
}实现 IEnumerable<T>
IEnumerable<T> 是 LINQ 和 foreach 的核心。实现该接口的类型可以进行迭代。通常,您可以委托给内部集合的迭代器。
使用带有 yield return 的迭代器方法可以轻松实现这一点。
using System.Collections;
using System.Collections.Generic;
class Bag<T> : IEnumerable<T>
{
private readonly List<T> items = new();
public void Add(T x) => items.Add(x);
public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}可运行的泛型接口
这个完整程序定义了泛型 IPrinter<T>,为字符串实现它,然后使用该实现。
无论具体类型是什么,该接口都保证存在 Print 方法。
using System;
interface IPrinter<T> { void Print(T value); }
class ConsolePrinter<T> : IPrinter<T>
{
public void Print(T value) => Console.WriteLine(value);
}
class Program
{
static void Main()
{
IPrinter<string> p = new ConsolePrinter<string>();
p.Print("hello generics");
}
}使用 out 的协变
标记为 out 的泛型接口参数具有协变性:它只能出现在输出位置。这样,在需要 IEnumerable<Animal> 的地方就可以使用 IEnumerable<Cat>。
协变性沿继承链保持赋值兼容性。
interface IProducer<out T>
{
T Produce();
}使用 in 的逆变
标记为 in 的参数具有逆变性:它只能出现在输入位置。这样,在需要 IComparer<Cat> 的地方就可以使用 IComparer<Animal>。
逆变性会反转消费者的可赋值方向。
interface IConsumer<in T>
{
void Consume(T item);
}多个类型参数
泛型接口可以接受多个参数。IDictionary<TKey, TValue> 是一个熟悉的示例,其中键类型和值类型彼此独立。
每个参数都可以独立地是不变、协变或逆变的。
interface IMapper<TIn, TOut>
{
TOut Map(TIn input);
}面向接口编程
依赖泛型接口而不是具体类,可以让代码更加灵活。无需修改调用方即可替换实现。
类型为 IEnumerable<T> 的方法参数可以同样接受列表、数组和查询结果。
using System.Collections.Generic;
using System.Linq;
int Total(IEnumerable<int> values) => values.Sum();使用泛型接口的约束
泛型接口经常用作约束。where T : IComparable<T> 可以让方法对输入进行排序或比较。
这将泛型的两项特性结合起来,从而构建安全且可复用的算法。
T Min<T>(T a, T b) where T : IComparable<T>
=> a.CompareTo(b) <= 0 ? a : b;快速检查
测试您对泛型接口的理解。
回顾
泛型接口声明类型参数,并允许实现者确定这些参数或将其继续传递。内置示例包括 IEnumerable<T>、IComparable<T> 和 IDictionary<TKey, TValue>。
方差注释 out 和 in 支持协变和逆变,泛型接口也可以自然地与 where 约束结合使用。
常见问题解答
「泛型接口」课时是免费的吗?
是的 — 「泛型接口」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「泛型接口」这节课中我会学到什么?
对类型进行抽象。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「泛型接口」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。