【C#基础:第四部分 高级特性】集合与泛型

摘要:本文围绕C#中的集合与泛型展开,详细介绍了ListDictionaryHashSet等常用集合类型,深入探讨了泛型约束、协变逆变的概念与应用,分析了IEnumerableIQueryable的区别与联系,还介绍了集合初始化器的使用方法。通过丰富的实操流程和完整代码示例,帮助读者全面理解和掌握C#中集合与泛型的高级特性,提升编程能力。


文章目录


请添加图片描述

【C#基础:第四部分 高级特性】集合与泛型

关键词

C#;集合;泛型;List;Dictionary;HashSet;泛型约束;协变逆变;IEnumerable;IQueryable;集合初始化器

一、引言

在C#编程中,集合与泛型是非常重要的高级特性。集合提供了一种方便的方式来存储和管理一组对象,而泛型则允许我们编写类型安全、可重用的代码。合理运用集合与泛型可以提高代码的性能、可读性和可维护性。本文将对C#中的集合与泛型进行深入探讨,通过实际案例和代码示例帮助读者更好地理解和应用这些特性。

二、List/Dictionary/HashSet

2.1 List

2.1.1 基本概念

List<T> 是一个动态数组,它可以根据需要自动调整大小。T 是泛型类型参数,表示列表中元素的类型。List<T> 提供了丰富的方法来操作列表元素,如添加、删除、查找等。

2.1.2 代码示例
using System;
using System.Collections.Generic;

class Program
{
   
    static void Main()
    {
   
        // 创建一个存储整数的 List
        List<int> numbers = new List<int>();

        // 添加元素
        numbers.Add(1);
        numbers.Add(2);
        numbers.Add(3);

        // 访问元素
        Console.WriteLine("列表中的第一个元素: " + numbers[0]);

        // 遍历列表
        Console.WriteLine("列表中的所有元素:");
        foreach (int num in numbers)
        {
   
            Console.WriteLine(num);
        }

        // 删除元素
        numbers.Remove(2);
        Console.WriteLine("删除元素 2 后,列表中的所有元素:");
        foreach (int num in numbers)
        {
   
            Console.WriteLine(num);
        }
    }
}
2.1.3 代码解释
  • 创建 List<int> 对象 numbers,用于存储整数。
  • 使用 Add 方法向列表中添加元素。
  • 通过索引访问列表中的元素,如 numbers[0]
  • 使用 foreach 循环遍历列表中的所有元素。
  • 使用 Remove 方法删除指定元素。
2.1.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件的 Main 方法中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

2.2 Dictionary<TKey, TValue>

2.2.1 基本概念

Dictionary<TKey, TValue> 是一个键值对集合,其中每个键都是唯一的。TKey 表示键的类型,TValue 表示值的类型。Dictionary<TKey, TValue> 提供了快速的查找功能,通过键可以快速定位到对应的值。

2.2.2 代码示例
using System;
using System.Collections.Generic;

class Program
{
   
    static void Main()
    {
   
        // 创建一个存储字符串键和整数值的 Dictionary
        Dictionary<string, int> scores = new Dictionary<string, int>();

        // 添加键值对
        scores.Add("Alice", 90);
        scores.Add("Bob", 85);
        scores.Add("Charlie", 78);

        // 访问元素
        Console.WriteLine("Alice 的分数: " + scores["Alice"]);

        // 遍历字典
        Console.WriteLine("所有学生的分数:");
        foreach (KeyValuePair<string, int> pair in scores)
        {
   
            Console.WriteLine(pair.Key + ": " + pair.Value);
        }

        // 删除键值对
        scores.Remove("Bob");
        Console.WriteLine("删除 Bob 的分数后,所有学生的分数:");
        foreach (KeyValuePair<string, int> pair in scores)
        {
   
            Console.WriteLine(pair.Key + ": " + pair.Value);
        }
    }
}
2.2.3 代码解释
  • 创建 Dictionary<string, int> 对象 scores,用于存储学生姓名和分数的键值对。
  • 使用 Add 方法向字典中添加键值对。
  • 通过键访问字典中的值,如 scores["Alice"]
  • 使用 foreach 循环遍历字典中的所有键值对。
  • 使用 Remove 方法删除指定键的键值对。
2.2.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件的 Main 方法中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

2.3 HashSet

2.3.1 基本概念

HashSet<T> 是一个无序的集合,其中每个元素都是唯一的。T 是泛型类型参数,表示集合中元素的类型。HashSet<T> 提供了高效的查找和插入操作,其内部使用哈希表来实现。

2.3.2 代码示例
using System;
using System.Collections.Generic;

class Program
{
   
    static void Main()
    {
   
        // 创建一个存储字符串的 HashSet
        HashSet<string> fruits = new HashSet<string>();

        // 添加元素
        fruits.Add("Apple");
        fruits.Add("Banana");
        fruits.Add("Apple"); // 重复元素不会被添加

        // 检查元素是否存在
        bool containsApple = fruits.Contains("Apple");
        Console.WriteLine("集合中是否包含 Apple: " + containsApple);

        // 遍历集合
        Console.WriteLine("集合中的所有元素:");
        foreach (string fruit in fruits)
        {
   
            Console.WriteLine(fruit);
        }

        // 删除元素
        fruits.Remove("Banana");
        Console.WriteLine("删除 Banana 后,集合中的所有元素:");
        foreach (string fruit in fruits)
        {
   
            Console.WriteLine(fruit);
        }
    }
}
2.3.3 代码解释
  • 创建 HashSet<string> 对象 fruits,用于存储水果名称。
  • 使用 Add 方法向集合中添加元素,重复元素不会被添加。
  • 使用 Contains 方法检查集合中是否包含指定元素。
  • 使用 foreach 循环遍历集合中的所有元素。
  • 使用 Remove 方法删除指定元素。
2.3.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件的 Main 方法中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

三、泛型约束与协变逆变

3.1 泛型约束

3.1.1 基本概念

泛型约束用于限制泛型类型参数的类型范围,确保泛型类型参数满足特定的条件。常见的泛型约束有以下几种:

  • where T : structT 必须是值类型。
  • where T : classT 必须是引用类型。
  • where T : new()T 必须有一个无参数的构造函数。
  • where T : baseClassT 必须是 baseClass 或其派生类。
  • where T : interfaceT 必须实现指定的接口。
3.1.2 代码示例
using System;

// 定义一个泛型类,使用泛型约束
class GenericClass<T> where T : IComparable<T>
{
   
    private T value;

    public GenericClass(T value)
    {
   
        this.value = value;
    }

    public bool IsGreaterThan(T other)
    {
   
        return value.CompareTo(other) > 0;
    }
}

class Program
{
   
    static void Main()
    {
   
        GenericClass<int> intObj = new GenericClass<int>(10);
        bool result = intObj.IsGreaterThan(5);
        Console.WriteLine("10 是否大于 5: " + result);
    }
}
3.1.3 代码解释
  • 定义了一个泛型类 GenericClass<T>,使用 where T : IComparable<T> 约束,确保 T 类型实现了 IComparable<T> 接口。
  • GenericClass<T> 类中,定义了一个 IsGreaterThan 方法,用于比较两个 T 类型的对象。
  • Main 方法中,创建了一个 GenericClass<int> 对象,并调用 IsGreaterThan 方法进行比较。
3.1.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

3.2 协变逆变

3.2.1 基本概念

协变和逆变是泛型接口和委托中的概念,用于处理泛型类型参数的转换。

  • 协变(Covariance):允许将一个派生类型的泛型对象赋值给一个基类型的泛型对象。协变使用 out 关键字修饰泛型类型参数。
  • 逆变(Contravariance):允许将一个基类型的泛型对象赋值给一个派生类型的泛型对象。逆变使用 in 关键字修饰泛型类型参数。
3.2.2 代码示例
using System;

// 定义一个协变接口
interface IAnimal<out T>
{
   
    T GetAnimal();
}

// 定义一个动物类
class Animal {
    }

// 定义一个狗类,继承自动物类
class Dog : Animal {
    }

// 实现协变接口
class DogProvider : IAnimal<Dog>
{
   
    public Dog GetAnimal()
    {
   
        return new Dog();
    }
}

class Program
{
   
    static void Main()
    {
   
        IAnimal<Dog> dogProvider = new DogProvider();
        IAnimal<Animal> animalProvider = dogProvider; // 协变转换
        Animal animal = animalProvider.GetAnimal();
        Console.WriteLine("获取到的动物类型: " + animal.GetType().Name);
    }
}
3.2.3 代码解释
  • 定义了一个协变接口 IAnimal<out T>,使用 out 关键字修饰泛型类型参数 T
  • 定义了 Animal 类和 Dog 类,Dog 类继承自 Animal 类。
  • 实现了 IAnimal<Dog> 接口的 DogProvider 类。
  • Main 方法中,将 IAnimal<Dog> 类型的对象赋值给 IAnimal<Animal> 类型的对象,实现了协变转换。
3.2.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

四、IEnumerable与IQueryable

4.1 IEnumerable

4.1.1 基本概念

IEnumerable<T> 是一个泛型接口,它定义了一个方法 GetEnumerator(),用于返回一个实现了 IEnumerator<T> 接口的枚举器对象。IEnumerable<T> 是 C# 中集合的基础接口,几乎所有的集合类型都实现了该接口。

4.1.2 代码示例
using System;
using System.Collections.Generic;

class Program
{
   
    static void Main()
    {
   
        List<int> numbers = new List<int> {
    1, 2, 3, 4, 5 };

        // 使用 IEnumerable<T> 进行遍历
        IEnumerable<int> enumerableNumbers = numbers;
        foreach (int num in enumerableNumbers)
        {
   
            Console.WriteLine(num);
        }
    }
}
4.1.3 代码解释
  • 创建一个 List<int> 对象 numbers,并初始化一些元素。
  • List<int> 对象赋值给 IEnumerable<int> 类型的变量 enumerableNumbers
  • 使用 foreach 循环遍历 enumerableNumbers,实际上是调用了 GetEnumerator() 方法获取枚举器对象进行遍历。
4.1.4 实操流程
  1. 打开 Visual Studio,创建一个新的 C# 控制台应用程序项目。
  2. 将上述代码复制到 Program.cs 文件的 Main 方法中。
  3. 按下 F5 键运行程序,观察控制台输出结果。

4.2 IQueryable

4.2.1 基本概念

IQueryable<T>IEnumerable<T> 的子接口,它提供了对数据的延迟查询功能。IQueryable<T> 通常用于与数据库等数据源进行交互,它会将查询表达式转换为相应的数据源查询语句,然后在需要时执行查询。

4.2.2 代码示例
using System;
using System.Collections.Generic;
using System.Linq;

class Person
{
   
    public string Name {
    get; set; }
    public int Age {
    get; set; }
}

class Program
{
   
    static void Main()
    {
   
        List<Person> people = new List<Person>
        {
   
            new Person {
    Name = "Alice", Age = 25 },
            new Person {
    Name = "Bob", Age = 30 },
            new Person {
    Name = "Charlie", Age = 35 }
        };

        // 将 List<Person> 转换为 IQueryable<Person>
        IQueryable<Person>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI_DL_CODE

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值