[C#2] 1-泛型

简介: 1. 泛型概述 泛型是一种类型的多态;比如当我们写一个栈或者队列的时候,需要指定其数据类型,int一份代码,string一份代码,object的一份代码, 这些代码除了数据类型不同之外其他大部分都是相同的,根据设计模式的思想,抽象出来变化点封装它, 共同的部分作为共用的代码。

1. 泛型概述

泛型是一种类型的多态;比如当我们写一个栈或者队列的时候,需要指定其数据类型,int一份代码,string一份代码,object的一份代码, 这些代码除了数据类型不同之外其他大部分都是相同的,根据设计模式的思想,抽象出来变化点封装它, 共同的部分作为共用的代码。这里的变化点就是类型了,共同部分就是算法相同,所以就把类型抽象化, 于是乎泛型问世&[个人理解]。

C#泛型由CLR在运行时支持,这使得泛型可以在CLR支持的各种语言上无缝集合; C#泛型代码在被编译[第一次编译]为IL代码和元数据时[泛型版的IL和元数据], 采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作,真正的泛型实例化工作发生在JIT编译[第二次编译]时。 当JIT编译器第一次遇到这种特殊的IL和元数据时,会利用实际的类型进行替换[泛型类型的实例化]。 CLR为所有类型参数是引用类型的泛型类型产生同一份代码,而对值类型来说,不同的值类型产生不同的代码, 相同的则共用同一份代码。

C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术;采用[基类, 接口, 构造器, 值类型/引用类型]的约束方式来实现对类型参数的"显式约束", 提高了类型的安全性。DEMO:

public class MyType<T> where T : struct
{
     private T[] _items;
     public void Add(T itme)
     {
     }
}

编译后IL如下:

//泛型类<'1代表元数或者参数数量>
.class public auto ansi beforefieldinit MyType`1<valuetype .ctor 
//注意这里加上了泛型约束<[mscorlib]System.ValueType) T>
//表明类型参数是值类型的
([mscorlib]System.ValueType) T>
    extends [mscorlib]System.Object
{
} // end of class MyType`1
//这是那个私有字段
.field private !T[] _items
 
//Add方法,类型参数<T>之前有一个感叹号<!>,这是CIL开始支持泛型
//后引入的新特性,它指出为类指定的第一个类型参数的存在,表明这是
//一个类型参数
.method public hidebysig instance void  Add(!T itme) cil managed
{
    // 代码大小       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
} // end of method MyType`1::Add

除了这些区别外,泛型类和非泛型类的CIL代码并无太大区别。

2. 泛型类型和泛型方法

可以用于泛型的类型有类、接口,结构、委托。

C#支持泛型方法,但不支持除方法外的其他成员[属性、事件、索引器、构造器、析构器。但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数]; 泛型方法可以包含在泛型类型中,也可以包含在非泛型类型中[即普通的类型]。泛型方法:

public class GenericsMehod
{
    //非泛型类中的泛型方法,参数约束为引用类型
    //<传入值类型参数将引起编译错误>
    public int FindItem<T>(T[] items, T item)where T:class
    {
        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].Equals(item))
            {
                return i;
            }
        }
        return -1;
    }
}

调用就不写了,泛型方法支持重载,但是之区别类型参数约束的重载是非法的; 也是支持重写的,重写时的类型参数的约束被默认继承,任何的约束的指定都是不必要的,也是不可以指定约束的。

3. 泛型约束

为什么要有约束呢?假如我写了一个泛型类,这个泛型参数调用到CompareTo方法, 但是并不是所有的类型参数都有这个方法,假如传入的类型没这个方法,就会引起错误了, 所以保证你的代码的健壮的话,加上约束还是很有必要的[就是说传入的类型必须有这个方法才可以编译通过, 把错误暴露在编译阶段]。泛型约束支持四种形式的约束【接口约束,基类约束,构造器约束,值类型/引用类型约束】; 约束并不是必须的,如果没有指定约束,那么类型参数将只能访问System.Object类型中的公有方法。语法为where语句

上面的类型参数需要一个CompareTo方法就可以用一个接口约束加以实现:

public class MyGenerics<T>; where T : IComparable{}

基类约束:表是类型参数必须是继承子指定的类型<where T : 基类>;

构造器约束:只支持无参的构造器约束,就是必须保障参数类型可以调用它的无参构造器<where T : new()>:

值类型/引用类型约束:只有两种情况了<where T:struct>或者<where T:class>,指定参数类型必须是值类型或者引用类型;

作者: Blackheart
目录
相关文章
|
18天前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
9月前
|
存储 算法 安全
C#三十二 泛型的理解和使用
C#三十二 泛型的理解和使用
22 0
|
18天前
|
存储 安全 Java
34.C#:listT泛型集合
34.C#:listT泛型集合
25 1
|
18天前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
197 2
|
18天前
|
存储 安全 算法
C# 泛型:类型参数化的强大工具
【1月更文挑战第7天】本文将深入探讨C#语言中的泛型编程,包括泛型的定义、用途、优势以及实际应用。通过类型参数化,泛型允许开发者编写更加灵活且可重用的代码,同时提高程序的类型安全性和性能。本文将通过示例代码和详细解释,帮助读者更好地理解泛型在C#中的重要性和实用性。
|
18天前
|
存储 Java 编译器
【从Java转C#】第五章:泛型
【从Java转C#】第五章:泛型
|
9月前
|
机器学习/深度学习 存储 缓存
一文带你搞懂C#泛型
泛型是.net 2.0中提供的新特性,是框架的一种升级,用于处理用一个事物来代替多种不同需求的情况。下面我们就一块来看一下具体的讲解吧。
|
10月前
|
安全 C#
c# 泛型约束
c# 泛型约束
|
11月前
|
存储 C# 索引
C#泛型集合常用方法
C#泛型集合常用方法
47 0
|
11月前
|
安全 C# 索引
C# 泛型集合和非泛型集合(List ArrayLIst)
C# 泛型集合和非泛型集合(List ArrayLIst)
67 0