目录
集合接口继承关系
基于接口的实现
主要接口
接口的作用
1. IEnumerable
2. IEnumerator
3. ICollection
4. IList
5. IDictionary,>
主要基类
基类的作用
1. Collection
2. List
3. Dictionary,>
4.LinkedList
5.HashSet
6.SortedList,>
7.Queue
8.Stack
在C#中,集合框架的设计遵循了OOP(面向对象编程)的原则,尤其是通过继承和接口的使用,使得不同类型的集合能够共享相同的基本行为和方法。
集合接口继承关系
IEnumerable<T>
└── ICollection<T>
└── IList<T>
└── List<T>
IEnumerable<T>
└── ICollection<KeyValuePair<TKey, TValue>>
└── IDictionary<TKey, TValue>
└── Dictionary<TKey, TValue>
IEnumerable<T>
└── ISet<T>
└── HashSet<T>
IEnumerable<T>
└── IReadOnlyCollection<T>
└── IReadOnlyList<T>
└── ReadOnlyCollection<T>
IEnumerable<T>
└── ICollection<T>
└── Queue<T>
IEnumerable<T>
└── ICollection<T>
└── Stack<T>
IEnumerable<T>
└── ICollection<T>
└── Collection<T>
├── ObservableCollection<T>
├── LinkedList<T>
└── SortedList<TKey, TValue>
基于接口的实现
集合框架中的基类实现了多个接口,提供具体的功能实现。
例如,List<T>
实现了 IList<T>
、ICollection<T>
和 IEnumerable<T>
。这使得 List<T>
可以通过这些接口进行操作,例如添加、删除和遍历元素。 实现接口的类可以被视为该接口类型。
在编写方法时,可以使用接口作为参数类型,从而实现对不同集合类型的一致操作。
public void PrintElements(IEnumerable<int> collection)
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
主要接口
接口是一种类型,它定义了一系列方法、属性、事件和索引器的签名,但并不提供具体的实现。接口本身不能被实例化,而是通过实现该接口的类或结构来提供实际的功能。
接口的作用
- 行为定义:接口定义了类应遵循的行为契约。实现相同接口的不同类可以表现出不同的行为,但它们都遵循相同的操作标准。
- 解耦合:通过依赖接口而不是具体实现,开发者可以降低类之间的耦合度,从而提高系统的灵活性和可维护性。
- 多态性:接口允许不同类的对象以相同的方式进行操作,支持多态设计。例如,
IEnumerable<T>
接口使得所有实现了该接口的集合类型都可以使用foreach
循环进行遍历。
1. IEnumerable<T>
- 功能:定义了一个用于迭代集合的基本约定。所有实现了
IEnumerable<T>
的集合都可以使用foreach
循环进行遍历。 - 基类关系:这是所有集合接口的基础,其他集合接口(如
ICollection<T>
和IList<T>
)都通过它来支持枚举。
public interface IEnumerable<T> {
IEnumerator<T> GetEnumerator();
}
2. IEnumerator<T>
- 功能:用于遍历集合的接口,提供对集合元素的访问和管理游标的位置。
- 基类关系:它是集合中用于支持迭代的关键接口,通常由实现了
IEnumerable<T>
的类返回。
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
T Current { get; }
}
3. ICollection<T>
- 功能:扩展了
IEnumerable<T>
,增加了对集合元素计数、添加、删除等功能的支持。 - 基类关系:它是
IEnumerable<T>
的子接口,也是IList<T>
和ISet<T>
的基础,提供对集合的基本操作。
public interface ICollection<T> : IEnumerable<T> {
int Count { get; }
bool IsReadOnly { get; }
void Add(T item);
void Clear();
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
bool Remove(T item);
}
4. IList<T>
- 功能:表示一个可索引的集合,允许通过整数索引访问元素,并提供插入和删除操作。
- 基类关系:继承自
ICollection<T>
,添加了索引访问的功能。
public interface IList<T> : ICollection<T>, IEnumerable<T>
{
T this[int index] { get; set; }
int IndexOf(T item);
void Insert(int index, T item);
void RemoveAt(int index);
}
5. IDictionary<TKey, TValue>
- 功能:表示一个键值对集合,允许通过键快速访问值。
- 基类关系:实现了
ICollection<KeyValuePair<TKey, TValue>>
接口,并用于方便地管理键值对。
public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
TValue this[TKey key] { get; set; }
ICollection<TKey> Keys { get; }
ICollection<TValue> Values { get; }
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
bool Remove(TKey key);
bool TryGetValue(TKey key, out TValue value);
}
主要基类
基类是一个具体的类,它可以包含实现、字段、属性和方法。基类可以被其他类继承,从而允许子类重用其实现,并可以扩展或重写这些方法。
基类的作用
- 代码重用:基类提供了一种机制,可以在类层次结构中共享通用功能,减少代码重复。例如,
Collection<T>
类实现了基础的集合操作,用于所有其他集合的基础。 - 状态管理:基类可以定义字段,提供共享的状态(数据)管理,使得子类可以继承并使用这些状态。
- 方法重写:基类可以定义虚方法或抽象方法,允许子类根据需要重写或实现这些方法,以便提供特定的行为。
1. Collection<T>
- 功能:提供了基本的集合操作,允许子类扩展和实现集合行为。
- 接口关系:实现了
ICollection<T>
和IEnumerable<T>
接口,作为其他集合类的基础。
// 泛型集合基类,提供基本的集合操作
public class Collection<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
// 内部使用的列表存储实际的元素
private readonly List<T> _items = new List<T>();
// 获取集合中元素的数量
public int Count => _items.Count;
// 判断集合是否是只读的,这里返回 false 表示可以修改
public bool IsReadOnly => false;
// 向集合添加元素的方法
public void Add(T item)
{
_items.Add(item);
// 触发集合更改的通知,通常用于 ObservableCollection 中
}
// 清空集合中的所有元素
public void Clear()
{
_items.Clear();
// 触发集合更改的通知
}
// 检查集合中是否包含指定的元素
public bool Contains(T item)
{
return _items.Contains(item);
}
// 将集合中的元素复制到指定数组中
public void CopyTo(T[] array, int arrayIndex)
{
_items.CopyTo(array, arrayIndex);
}
// 返回用于迭代集合的枚举器
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
// 封装 IEnumerable 接口的未泛型版本
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
// 索引器,允许通过索引访问集合中的元素
public T this[int index]
{
get => _items[index]; // 返回指定索引的元素
set
{
_items[index] = value; // 设置指定索引的元素
// 触发集合更改的通知
}
}
}
- 字段:
_items
是基础的存储容器,通常使用List<T>
来实现内部存储。 - Count 属性:返回集合中元素的数量。
- Add 方法:添加新元素到集合,并可以触发更改通知(通常在
ObservableCollection<T>
中使用)。 - GetEnumerator 方法:实现了
IEnumerable<T>
接口,允许使用foreach
循环遍历集合。 - 索引器:通过索引访问集合中的元素,支持
this[int index]
。
2. List<T>
- 功能:提供动态数组的实现,支持按索引访问和其他常用集合操作。
- 接口关系:继承自
Collection<T>
,实现了IList<T>
和IEnumerable<T>
,因此可以使用集合的基础操作。
// 泛型动态数组集合,支持索引访问
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlyList<T>
{
// 存储元素的数组
private T[] _items;
// 当前元素的数量
private int _size;
// 版本号,用于跟踪集合的更改
private int _version;
// 默认构造函数,初始化为一个空数组
public List()
{
_items = Array.Empty<T>();
}
// 向集合添加新元素的方法
public void Add(T item)
{
// 检查数组是否已满,若满则扩展容量
if (_size == _items.Length)
{
EnsureCapacity(_size + 1);
}
_items[_size++] = item; // 将新元素添加到数组
_version++; // 增加版本号
}
// 获取或设置集合的容量
public int Capacity
{
get => _items.Length; // 返回当前容量
set
{
// 如果新容量小于当前元素数量,抛出异常
if (value < _size) throw new ArgumentOutOfRangeException();
if (value != _items.Length)
{
if (value > 0)
{
// 创建新的数组并复制原数组的元素
var newItems = new T[value];
if (_size > 0)
{
Array.Copy(_items, newItems, _size);
}
_items = newItems; // 更新内部存储数组
}
else // 若容量为 0,则清空数组
{
_items = Array.Empty<T>();
}
}
}
}
// 返回当前元素数量
public int Count => _size;
// 索引器,允许通过索引访问和修改元素
public T this[int index]
{
get => _items[index]; // 获取指定索引的元素
set => _items[index] = value; // 设置指定索引的元素
}
// 确保数组具有足够的容量
private void EnsureCapacity(int min)
{
// 如果当前容量不足,则进行扩展
if (_items.Length < min)
{
int newCapacity = _items.Length == 0 ? 4 : _items.Length * 2; // 计算新容量
if (newCapacity < min) newCapacity = min; // 确保新容量不小于所需容量
Capacity = newCapacity; // 设置新容量
}
}
// 其他方法略...
}
- 字段:
_items
是实际存储元素的数组,_size
是当前元素数量,_version
用于跟踪集合的变化,支持集合的并发操作。 - Add 方法:添加元素时首先检查当前容量,如果数组已满,则通过
EnsureCapacity
方法扩展容量。 - Capacity 属性:用于获取或设置集合的容量,确保集合能容纳更多元素。
- 索引器:支持通过索引访问和设置元素。
3. Dictionary<TKey, TValue>
- 功能:基于哈希表的实现,用于存储和快速查找键值对。
- 接口关系:实现了
IDictionary<TKey, TValue>
接口,并继承ICollection<KeyValuePair<TKey, TValue>>
,提供对键值对的管理。
// 泛型字典实现,基于哈希表,用于存储键值对
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
// 哈希桶,存储每个键的索引
private int[] _buckets;
// 存储实际键值对的数组
private Entry[] _entries;
// 当前元素的数量
private int _count;
// 定义字典中每个元素的结构
private struct Entry
{
public int hashCode; // 哈希值
public int next; // 指向下一个条目的索引
public TKey key; // 键
public TValue value; // 值
}
// 默认构造函数,初始化哈希桶和条目数组
public Dictionary()
{
// 初始化逻辑,例如设置初始容量
}
// 添加键值对到字典
public void Add(TKey key, TValue value)
{
// 插入逻辑,包括处理冲突
}
// 根据键获取值
public bool TryGetValue(TKey key, out TValue value)
{
// 查找逻辑,根据键计算哈希并定位到对应的值
}
// 从字典中删除特定的键值对
public bool Remove(TKey key)
{
// 删除逻辑,更新哈希桶
}
// 索引器,用于访问和设置字典中的值
public TValue this[TKey key]
{
get
{
if (!TryGetValue(key, out TValue value))
{
throw new KeyNotFoundException(); // 如果未找到键,抛出异常
}
return value; // 返回找到的值
}
set => Add(key, value); // 设置值时调用添加方法
}
// 其他方法略...
}
4.LinkedList<T>
- 功能:表示一个双向链表,支持在任意位置快速插入和删除元素。
- 接口关系:没有直接的接口实现,但可用于构建其他集合类型,如
Queue<T>
和Stack<T>
。
public class LinkedList<T>
{
private LinkedListNode<T> _first; // 链表的第一个节点
private LinkedListNode<T> _last; // 链表的最后一个节点
public LinkedList() { }
// 添加新节点到链表的末尾
public void AddLast(T value)
{
var newNode = new LinkedListNode<T>(value);
if (_last == null)
{
_first = newNode; // 如果链表为空,设置头尾节点
_last = newNode;
}
else
{
_last.Next = newNode; // 设置上一个节点的 Next 指针
newNode.Previous = _last; // 设置新节点的 Previous 指针
_last = newNode; // 更新最后一个节点
}
}
// 删除指定节点
public bool Remove(LinkedListNode<T> node)
{
if (node == null) return false; // 检查节点有效性
if (node.Previous != null)
{
node.Previous.Next = node.Next; // 更新前驱节点的 Next 指针
}
if (node.Next != null)
{
node.Next.Previous = node.Previous; // 更新后继节点的 Previous 指针
}
// 更新头尾节点
if (node == _first) _first = node.Next;
if (node == _last) _last = node.Previous;
return true; // 返回删除成功
}
}
public class LinkedListNode<T>
{
public T Value { get; set; } // 节点存储的值
public LinkedListNode<T> Next { get; set; } // 指向下一个节点
public LinkedListNode<T> Previous { get; set; } // 指向前一个节点
public LinkedListNode(T value)
{
Value = value; // 构造函数,初始化值
}
}
5.HashSet<T>
- 功能:提供不允许重复元素的集合,使用哈希表实现,支持集合运算。
- 接口关系:实现了
ISet<T>
接口,继承自ICollection<T>
,提供基本集合操作。
public class HashSet<T>
{
private Dictionary<T, bool> _dictionary; // 使用字典存储元素
public HashSet()
{
_dictionary = new Dictionary<T, bool>(); // 初始化字典
}
// 添加元素
public bool Add(T item)
{
if (_dictionary.ContainsKey(item))
return false; // 如果元素已经存在,返回 false
_dictionary[item] = true; // 添加元素,值设置为 true
return true; // 返回 true 表示添加成功
}
// 删除元素
public bool Remove(T item)
{
return _dictionary.Remove(item); // 使用字典的 Remove 方法
}
// 检查集合是否包含指定元素
public bool Contains(T item)
{
return _dictionary.ContainsKey(item); // 使用字典的 ContainsKey 方法
}
}
6.SortedList<TKey, TValue>
- 功能:提供基于键的排序的集合,使用键/值对的形式保存数据,支持通过键进行快速查找。
- 接口关系:实现了
IDictionary<TKey, TValue>
接口,用于定义键值对的集合。
public class SortedList<TKey, TValue>
{
private List<TKey> _keys; // 存储键的列表
private List<TValue> _values; // 存储值的列表
public SortedList()
{
_keys = new List<TKey>();
_values = new List<TValue>();
}
// 添加键值对,保持键的有序性
public void Add(TKey key, TValue value)
{
int index = _keys.BinarySearch(key); // 查找插入位置
if (index < 0) index = ~index; // 索引为负表示未找到,取反得到插入位置
_keys.Insert(index, key);
_values.Insert(index, value); // 在相同位置插入值
}
// 通过键获取值
public TValue this[TKey key]
{
get
{
int index = _keys.IndexOf(key);
if (index < 0) throw new KeyNotFoundException(); // 找不到键抛出异常
return _values[index]; // 返回对应的值
}
}
}
7.Queue<T>
- 功能:表示先进先出(FIFO)的集合,适合在需要排队处理的场景下使用。
- 接口关系:通过使用
LinkedList<T>
作为内部数据结构,支持接口IEnumerable<T>
。
public class Queue<T>
{
private LinkedList<T> _list; // 使用链表存储元素
public Queue()
{
_list = new LinkedList<T>(); // 初始化链表
}
// 添加元素到队列末尾
public void Enqueue(T item)
{
_list.AddLast(item); // 调用链表的添加方法
}
// 从队列头部移除并返回元素
public T Dequeue()
{
if (_list.Count == 0) throw new InvalidOperationException("Queue is empty.");
var value = _list.First.Value; // 获取头部元素
_list.Remove(_list.First); // 从链表中移除头部元素
return value; // 返回头部元素
}
}
8.Stack<T>
- 功能:表示后进先出(LIFO)的集合,使用栈结构来存储元素。
- 接口关系:同样使用
LinkedList<T>
作为内部结构,支持迭代。
public class Stack<T>
{
private LinkedList<T> _list; // 使用链表存储元素
public Stack()
{
_list = new LinkedList<T>(); // 初始化链表
}
// 将元素推入栈中
public void Push(T item)
{
_list.AddLast(item); // 调用链表的添加方法
}
// 从栈中弹出元素
public T Pop()
{
if (_list.Count == 0) throw new InvalidOperationException("Stack is empty.");
var value = _list.Last.Value; // 获取栈顶元素
_list.Remove(_list.Last); // 从链表中移除栈顶元素
return value; // 返回栈顶元素
}
}