C#精挑整理知识要点10 泛型(建议收藏)

1.泛型的概念

定义:泛型允许我们延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。(也就是说泛型是可以与任何数据类型一起工作的类或方法)模块内高内聚,模块间低耦合。

泛型的使用:当我们的类/方法不需要关注调用者传递的实体是什么(公共基类工具类),这个时候就可以使用泛型。

注意:

集合中的项允许是 object 型的值,因此可以存放任意类型的值,无法确保存入集合中的值都是同一类型,而导致在处理时发生异常。

2.可空类型

对于引用类型的变量来说,如果未对其赋值,在默认情况下是 Null 值,对于值类型的变量,如果未赋值,整型变量的默认值为 0。

但通过 0 判断该变量是否赋值了是不太准确的。在 C# 语言中提供了一种泛型类型(即可空类型 (System.Nullable))来解决值类型的变量在未赋值的情况下允许为 Null的情况。

可空类型的定义

System.Nullable<T> 变量名;
类型? 变量名;

可空类型常用方法:

属性或方法作用
HasValue若变量有值则为True,若为null则为False
Value返回可空类型变量中存储的真正的值,当HasValue为True时才可以使用

例:

class Program
{
    static void Main(string[] args)
    {
        int? i = null;
        double? d = 3.14;
        if(i.HasValue)
        {
            Console.WriteLine("i的值为{0}",i);
        }
        else
        {
        	Console.WriteLine("i的值为空!");    
        }
        if(d.HasValue)
        {
            Console.WriteLine("d的值为{0}",d);
        }
        else
        {
            Console.WriteLine("d的值为空!")
        }
    }
}

3.泛型方法

在 C# 语言中泛型方法是指通过泛型来约束方法中的参数类型,也可以理解为对数据类型设置了参数。

如果没有泛型,每次方法中的参数类型都是固定的,不能随意更改。

在使用泛型后,方法中的数据类型则有指定的泛型来约束,即可以根据提供的泛型来传递不同类型的参数。

泛型方法的定义:

定义泛型方法需要在方法名和参数列表之间加上<>,并在其中使用 T 来代表参数类型。

注意:

C#中泛型方法中只能使用object类具有的方法。

例:

class Program
{
    static void Main(string[] args)
    {
        //将T设置为double类型
        GenericFunc<double>(3.3,4);
        //将T设置为int类型
        GenericFunc<int>(3,4);
    }
    
    //泛型方法
    private static void GenericFunc<T>(T a,T b)
    {
        Console.WriteLine("参数1:{0},类型:{1},参数2:{2},类型:{3}",a,a.GetType(),b,b.GetType());
    }
    
    
    
}

4.泛型类

C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上,当然,也可以定义多个类型,即“<T1,T2,・・・>”。

定义形式:

class 类名<T1,T2,……>
{
    //类的成员
}

这样,在类的成员中即可使用 T1、T2 等类型来定义。

例:

/// <summary> 
/// 自定义泛型类 
/// </summary> 
/// <typeparam name="T"></typeparam>
class MyTest<T>
{
    private T[] items = new T[3];
    private int index = 0;
    //向数组中添加项
    public void Add(T t)
    {
        if(index<3)
        {
            items[index] = t;
            index++;
        }
        else{
            Console.WriteLine("数组已满!");
        }
    }
    //读取数组中的全部项
    public void Show()
    {
        foreach(T t in items)
        {
            Console,WriteLine(t);
        }
    }
}

5.泛型中的数据约束

泛型中的数据约束可以指定泛型类型的范围。

若给T类型的数据约束struct,则T只能接受struct的子类类型,否则编译错误

例:

/// <summary> 
/// 限定了类型的范围:只能是IShape接口的实现类 
/// </summary> 
/// <typeparam name="T"></typeparam>
class MyTest<T> where T:Ishape
{
    private T[] items = new T[3];
    private int index = 0;
    //向数组中添加项
    public void Add(T t)
    {
        if(index<3)
        {
            items[index] = t;
            index++;
        }
        else
        {
            Console.WriteLine("数组已满!");
        }
    }
    //读取数组中的全部项
    public void Show()
    {
        foreach(T t in items)
        {
            Console.WriteLine(t);
        }
    }
}


class Program
{
    static void Main(string[] args)
    {
        MyTest<Rectangle> testObj = new MyTest<Rectangle>();
        
        testObj.Add(new Rectangle(100,200));
        testObj.Add(new Rectangle(50,50));
        
        testObj.Show();
    }
}

6.泛型集合

C# 语言中泛型集合是泛型中最常见的应用,主要用于约束集合中存放的元素。

由于在集合中能存放任意类型的值,在取值时经常会遇到数据类型转换异常的情况,因此推荐在定义集合时使用泛型集合。

泛型集合中主要使用 List 和 Dictionary<K,V> 。

1.List< T >类

List类是 ArrayList 类的泛型等效类。该类使用大小可按需动态增加的数组实现IList 泛型接口。

例:

class Program
{
    static void Main(string[] args)
    {
        //定义泛型集合
        List<int> list = new List<int>();
        //向集合中存入3个变量
        list.Add(5);
        list.Add(10);
        list.Add(15);
        //遍历集合中的元素
        foreach (var i in list)
        {
            Console.WriteLine(i);
        }
    }
}
2.Dictionary<K,V>

Dictionary<K,V>是 HashTable相对应的泛型集合,其存储数据的方式与哈希表相似,通过键/值来保存元素,并具有泛型的全部特征,编译时检查类型约束,读取时无须类型转换。

使用约束

  • 从一组键(Key)到一组值(Value)的映射,每一个添加项都是由一 个值及其相关连的键组成

  • 任何键都必须是唯一的

  • 键不能为空引用null,若值为引用类型,则可以为空值

  • Key和Value可以是任何类型(string,int,class 等)

例:

class Program
{
    static void Main(string[] args)
    {
        Dictionary<int,Student> dictionary = new Dictionary<int,Student>();
        Student stu1 = new Student(1,"小曾",19);
        Student stu2 = new Student(2,"小嘉",19);
        Student stu3 = new Student(3,"小怡",19);
        dictionary.Add(stu1.id,stu1);
        dictionary.Add(stu2.id,stu2);
        dictionary.Add(stu3.id,stu3);
        Console.WriteLine("请输入学号:");
        int id = int.Parse(Console.ReadLine());
        if(dictionary.ContainsKey(id))
        {
            Console.WriteLine("学生信息为:{0}", dictionary[id]);
        }
        else
        {
            Console.WriteLine("您查找的学号不在!");
        }
    }
}

7.IComparable、IComparer自定义排序

在 C# 语言中提供了 IComparer 和 IComparable 接口比较集合中的对象值,主要用于对集合中的元素排序。

IComparer 接口用于在一个单独的类中实现,用于比较任意两个对象。

IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。

在比较器中还提供了泛型接口的表示形式,即 IComparer 和 IComparable 的形式

1.IComparable< T > 接口

要比较的自定义类型需要继承IComparable < T > 接口,并实现以下方法

方法作用
CompareTo(T obj)比较两个对象值,返回值小于0代表当前实例小于比较实例 ,返回值等于0代表二者相等,返回值大于0代表当前实例大于比较实例

如果需要对集合中的元素排序,通常使用 CompareTo 方法实现,下面通过实例来演示CompareTo 方法的使用

class Student:IComparable<Student>
{
    //提供有参构造方法,为属性赋值
    public Student(int id,string name,int age)
    {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    //学号
    public int id{get;set;}
    //姓名
    public string name{get;set;}
    //年龄
    public int age{get;set;}
    //重写Tostring方法
    public override string ToString()
    {
        return id + ":" + name + ":" + age;
    }
     //定义比较方法,按照学生的年龄比较
    public int CompareTo(Student other)
    {
        if(this.age<other.age)
        {
            return -1;
        }
        else if(this.age==other.age)
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }
}



class Program
{
    static void Main(string[] args)
    {
        //创建一个泛型列表,列表中的元素类型为Student
        List<Student> stuList = new List<Sudent>();
        //在元素中添加三个元素
        stuList.Add(new Student(3,"小曾",19));
        stuList.Add(new Student(1,"小嘉",19));
        stuList.Add(new Student(2,"小怡",19));
        //遍历并输出
        foreach(var stu in stuList)
        {
            console.WriteLine(stu);
        }
    }
}
2、 IComparer < T > 接口

如果要使得自定义类型可以使用泛型集合中的Sort方法进行排序,那么可自定义一个排序类,实现IComparer < T > 接口中的以下方法:

方法作用
Compare(T obj1,T obj2)比较两个对象值 ,返回值小于0代表当前实例小于比较实例,返回值等于0代表二者相等,返回值大于0代表当前实例大于比较实例

新建学生类型排序类StudentComparer ,实现IComparer< Student >接口。

例:

/// <summary> 
/// 比较类,用于两个Student对象比较 
/// </summary>
class StudentComparer:IComparer<Student>
{
    /// <summary> 
    /// 比较方法 
    /// </summary> 
    /// <param name="x"></param>
    /// <param name="y"></param> 
    /// <returns></returns>
    public int Comparer(Student x,Student y)
    {
        if(x.age<y.age)
        {
            return 1;
        }
        else if(x.age>y.age)
        {
        	return -1;
        }
        else
        {
            return 0;
        }
    }
}


class Program
{
    static void Main(string[] args)
    {
        //创建一个泛型列表,列表中的元素类型为Student
        List<Student> stuList = new List<Student>();
         //在元素中添加三个元素 
        stuList.Add(new Student(3, "张三", 20)); 
        stuList.Add(new Student(1, "李四", 15)); 
        stuList.Add(new Student(2, "王五", 18));
        
        //遍历并输出
        foreach(var stu in stuList)
        {
            Console.WriteLine(stu);
        }
        
        Console.WriteLine("排序后:");
        //排序
        stuList.Sort(new StudentComparer());
        //遍历并输出
        foreach(var stu in stuList)
        {
            Console.WriteLine(stu);
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

꧁小ۣۖิ鸽ۣۖิ子ۣۖิ꧂

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

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

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

打赏作者

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

抵扣说明:

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

余额充值