CodeGym /课程 /C# SELF /C#集合中接口的作用

C#集合中接口的作用

C# SELF
第 28 级, 课程 0
可用

1. 集合为啥要用接口?

说实话:当我们用具体类型写代码的时候(List<int>、Dictionary<string, string>),一切都很简单明了。但你想象下,突然你想把List<T>换成HashSet<T>,因为你只需要唯一值。或者你想写个方法,能同时处理这两种集合类型。咋办?

你得有个统一的“接口”——C#里这个“接口”就是接口(interface)。它规定了一套规则(方法、属性),集合必须有这些东西。只要实现了接口——就能支持这些操作。

就像手机充电:有了标准的USB-C接口,你能给手机充电,也能给现代吸尘器、甚至电动牙刷充电(就是别在黑灯瞎火的时候搞混了)。

实际例子

比如你想写个方法,算任意数字集合的和。如果不用接口,大概是这样:


// 这个方法只能处理数组:
static int SumArray(int[] array)
{
    int sum = 0;
    for (int i = 0; i < array.Length; i++)
    {
        sum += array[i];
    }
    return sum;
} 

// 这个只能处理List<int>:
static int SumList(List<int> list)
{
    int sum = 0;
    for (int i = 0; i < list.Count; i++)
        sum += list[i];
    return sum;
}

很不方便吧!其实代码几乎一样。用IEnumerable<int>接口就能写成通用的:


static int SumAll(IEnumerable<int> collection)
{
    int sum = 0;
    foreach (var number in collection)
        sum += number;
    return sum;
}

现在这个方法能接收任何实现了IEnumerable<int>的集合类型:数组、列表、集合啥的都行。

2. 集合的主要接口

.NET里集合有几个核心接口。咱们先简单过一遍——后面课程会细讲每个的实现细节。

接口 作用 实现该接口的集合例子
IEnumerable<T>
遍历元素(foreach) 所有:
List<T>
、
HashSet<T>
、数组
ICollection<T>
可变集合(Add、Remove、Count)
List<T>
、
HashSet<T>
、
Dictionary<K,V>
IList<T>
按索引访问、修改
List<T>
、数组
IDictionary<K,V>
处理“键-值”对
Dictionary<K,V>
、
SortedDictionary<K,V>
ISet<T>
集合(唯一元素)
HashSet<T>
、
SortedSet<T>

P.S. 为了简单起见,暂时不讲这些接口之间的“多层继承”关系。谁继承谁——后面再说。

可视化:集合接口树


           IEnumerable<T>
                 ^
                 |
          ICollection<T>
              ^       ^
              |       |
         IList<T>  ISet<T>
              |       |
         List<T>   HashSet<T>
列表和集合的接口继承关系

对于字典:


           IEnumerable<KeyValuePair<K,V>>
                      ^
                      |
               ICollection<KeyValuePair<K,V>>
                      ^
                      |
               IDictionary<K,V>
                      |
                Dictionary<K,V>
字典的接口继承关系

3. 现实中接口有啥用?

灵活性

当你的方法或类操作的不是具体类型(List<int>),而是接口(IEnumerable<int>),你就能传入任何实现了这个接口的集合。这样程序就变得灵活、可扩展。(不再是“只能用iPhone”——现在只要有蓝牙的手机都行。)


static void PrintAll(IEnumerable<string> collection)
{
    foreach (var item in collection)
        Console.WriteLine(item);
}

现在你可以打印任何列表、数组、集合,甚至LINQ查询的结果!

统一

如果你实现了自己的集合类型(比如某个很特殊的集合),只要实现了需要的接口——你的集合就能和别人的代码配合,哪怕他们根本不知道你的集合类型。这也是为啥.NET里常说:“面向接口编程,而不是面向具体实现”。

兼容标准工具

支持标准接口后,你的集合能和LINQ、排序、序列化等.NET功能无缝配合。

4. List<T>——既是列表、又是集合、还是可遍历的

关于遍历的几句话

IEnumerable<T>是.NET里最重要、最基础的集合接口。它只定义了一个方法——GetEnumerator(),返回一个枚举器(Enumerator),用来遍历集合。正因为有它,你才能写:


foreach (var name in names)
{
    Console.WriteLine(name);
}

这里names可以是列表、集合,甚至数组。foreach其实是语法糖,底层就是用GetEnumerator()方法。

IEnumerable(没有<T>)是更老的、非泛型的版本。现在基本都用泛型的。

List类的声明语法

来看看List<T>类的声明,稍微揭秘下它的魔法:


public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, ...

这意味着List<T>对象可以当作:

  • 支持索引访问的列表(IList<T>)
  • 能增删元素的集合(ICollection<T>)
  • 可以遍历的元素集合(IEnumerable<T>)

例子:


List<string> names = new List<string> { "安娜", "鲍里斯", "瓦夏" };

// 作为IEnumerable - 可以遍历
IEnumerable<string> asEnumerable = names;
foreach (var n in asEnumerable) Console.WriteLine(n);

// 作为ICollection - 可以获取Count:
ICollection<string> asCollection = names;
int count = asCollection.Count;

// 作为IList - 可以按索引访问:
IList<string> asList = names;
string firstItem = asList[0];

5. 应用实例

比如我们有个简单的用户和角色管理应用(上节课刚开始写的):


// 用户类
public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

我们可以把用户存在任何实现了IEnumerable<User>的集合里:


List<User> listUsers = new List<User> { new User { Name = "安娜", Age = 20 } };
HashSet<User> setUsers = new HashSet<User> { new User { Name = "鲍里斯", Age = 25 } };

// 输出所有用户名字的方法
static void PrintUserNames(IEnumerable<User> users)
{
    foreach (var user in users)
        Console.WriteLine(user.Name);
}

// 用不同类型的集合调用:
PrintUserNames(listUsers);
PrintUserNames(setUsers);

现在应用变得超级灵活——不用魔法,也不用写一堆重载!

6. 常见错误和坑

最常见的错误之一——用太具体的类型,其实用接口就够了:


// 不好(死死绑在实现上)
void DoSomethingWithList(List<int> numbers) { ... }

// 更好(方法能处理任何集合)
void DoSomethingWithNumbers(IEnumerable<int> numbers) { ... }

还有个坑——别忘了接口只规定了它声明的那些操作。比如IEnumerable<T>没法获取元素数量(Count),你得用ICollection<T>,或者自己数一遍。

2
任务
C# SELF, 第 28 级, 课程 0
已锁定
为自定义集合实现接口 IEnumerable
为自定义集合实现接口 IEnumerable
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION