首页 > 编程语言 >C# 泛型简单概括

C# 泛型简单概括

时间:2024-08-10 19:26:16浏览次数:14  
标签:Console C# GetType 接口 概括 WriteLine 类型 泛型

一、泛型的概念,定义,运行原理,优势

1.泛型的概念

泛型(generic)是C# 2.0推出的新语法,并不是语法糖,它是专门为处理多段代码在不同的数据类型上执行相同的指令的情况而设计的。
即泛型让不同的数据类型支持相同的业务逻辑。

泛型是一个复合类型,把多个类型混合一起作用,比如:方法和泛型混到一起,叫泛型方法,类和泛型混在一起叫泛型类,接口和泛型混到一起,叫泛型接口,等等。

2.泛型该如何定义

泛型定义语法格式:<T>或<T,K,......> 其中T,K指未知类型。

语句:Class Show<T>

使用:Show<类型> show=new Show<类型>();
泛型定义时,是延迟声明的:即定义的时候没有指定具体的参数类型,把参数类型的声明推迟到了调用的时候才指定参数类型。

3.泛型的运行原理

程序最终会编译成XXX.exe,XXX.exe被点击的时候,会经过JIT的编译,生成二进制代码,才被计算机执行。使用泛型以后,VS自带的编译器又做了升级,升级之后编译时遇到泛型,会做特殊的处理:先生成占位符。再次经过JIT编译的时候,会把上面编译生成的占位符替换成具体的数据类型。(两次编译) 
注解:JIT:Just In Time称为即时编译器

4.泛型的优势 

1.最大限度地重用代码(支持多种数据类型)。
2.保护类型的安全以及提高性能(和object相比,object会使用到装箱操作)。
3.语法优美

二、泛型的应用范围

泛型方法,泛型接口,泛型类,泛型委托,泛型结构

但在C#中应用比较广的泛型:泛型方法,泛型类,泛型接口

泛型可以提供多种数据类型的占位符

 internal class Program
 {
     static void Main(string[] args)
     {
         //这里把T变为int,K变为float,
         Stort<int,float> stack=new Stort<int,float>();
     }
 }
 //这里T和K都为占位符
 class Stort<T,K>
 {
    public T Value { get; set; }
     public K Key { get; set; }
 }

1.泛型方法

泛型方法是通过类型参数声明的方法,调用时泛型参数类型可以省略

泛型方法:Show<T>是方法名称  <T>T是未知类型,不区分大小写,但建议使用大写,且尽量使用这些字母:T,K,V,M,N

 public static void Show<T>(T i)
 {
     Console.WriteLine($"方法所在的类名:{typeof(Common).Name},参数的类型名称:{i.GetType().Name},参数值:{i}");
 }

泛型方法参数的类型在编译时可以确定( 时机:编译时,运行时)

定义时注意一下3点:
1.参数的未知类型在方法名称后面的<> 中定义。
2.参数的未知类型在方法局部作用域中可以使用。
3.参数的未知类型能定义几个?理论上是无限

例子:有一个静态类,它中有三个方法,分别显示类的类型名称,方法参数的类型名称,方法参数值

// 三个方法:拥有相同的业务逻辑(相同指令),缺点:代码冗余,重复
public static void ShowInt(int i) {
    Console.WriteLine($"方法所在的类名:{typeof(Common).Name},参数的类型名称:{i.GetType().Name},参数值:{i}");
}
public static void ShowString(string i)
{
    Console.WriteLine($"方法所在的类名:{typeof(Common).Name},参数的类型名称:{i.GetType().Name},参数值:{i}");
}
public static void ShowDateTime(DateTime i)
{
    Console.WriteLine($"方法所在的类名:{typeof(Common).Name},参数的类型名称:{i.GetType().Name},参数值:{i}");
}

// 获取类型有两种方式:
// a. typeof一般用来获取引用类型的变量类型。
// b. GetType()是通用的。
public static void ShowInt(int i, string str)
{
    // typeof判断引用类型
    Console.WriteLine(typeof(Common).Name);
    Console.WriteLine(typeof(Common).Namespace);
    Console.WriteLine(typeof(Common).FullName);
    Console.WriteLine(typeof(Common).GUID);
    Console.WriteLine("---------------------");
    Console.WriteLine(str.GetType().Name);
    Console.WriteLine(str.GetType().Namespace);
    Console.WriteLine(str.GetType().FullName);
    Console.WriteLine(str.GetType().GUID);
    Console.WriteLine("---------------------");
    // GetType()方法是通用的,可以获取值类型或引用类型的具体类型。
    Console.WriteLine(i.GetType().Name);
    Console.WriteLine(i.GetType().Namespace);
    Console.WriteLine(i.GetType().FullName);
    Console.WriteLine(i.GetType().GUID);
}

2.泛型类

泛型类封装不特定于特定数据类型的操作。 泛型类最常见用法是用于链接列表、哈希表、堆栈、队列和树等集合。 无论存储数据的类型如何,添加项和从集合删除项等操作的执行方式基本相同。

创建泛型类是从现有具体类开始,然后每次逐个将类型更改为类型参数,直到泛化和可用性达到最佳平衡。

泛型类是 C# 中一个非常重要的概念,它们在实际编程中被广泛使用,特别是在需要处理集合和数据结构时。

例子:用泛型类进行排序,可以对实现了IComparable<T>接口的任何类型进行排序

using System;
using System.Collections.Generic;
namespace 泛型类
{
    internal class GenericSorter<T> where T : IComparable<T>
    {
        private List<T> list;
        public GenericSorter()
        {
            list = new List<T>();
        }
        public void Add(T item)
        {
            list.Add(item);//将对象添加到 List<T> 的结尾处。也就是list
        }
        public void Sort()
        {
            list.Sort();// 使用.NET内置的Sort方法,它利用了IComparable<T>接口
        }
        public List<T> Getlist()
        {
            return list;
        }
    }
}

using System;
namespace 泛型类
{
    internal class Program
    {      
        static void Main(string[] args)
        {
           GenericSorter<int> intSorter = new GenericSorter<int>();
            intSorter.Add(5);
            intSorter.Add(2);
            intSorter.Add(1);
            intSorter.Add(4);
            intSorter.Sort();
            Console.WriteLine("排好的顺序为"+string.Join(" ",intSorter.Getlist()));//排好的顺序为1 2 4 5
            Console.ReadLine();
        }
    }
}

3.泛型接口

泛型接口和泛型类定义方式一样,在接口名称后使用<T>未知类型,为泛型集合类或表示集合中的项的泛型类定义接口通常很有用处。

使用了泛型定义的接口就是泛型接口。

格式:修饰符 interface 接口名<T>{ }

三、泛型约束

泛型的目的:相同的业务逻辑,支持了不同类型。但一味的滥用,则对代码安全性不利。

引入泛型约束主要控制泛型支持的类型在有限的范围内。

所谓的泛型约束,实际上就是约束的类型T 。使T必须遵循一定的规则。比如T必须继承自某个类,或者T必须实现某个接口等等。

给泛型指定约束:需要where关键字,加上约束的条件。如:where T: class

泛型约束的好处: 让代码异常出现在编译期间,而非运行期间,从而增强代码的安全性。

五种常用的泛型约束:

T:class 引用类型约束保证T一定是引用类型的。
T:结构  值类型约束保证T一定是值类型的。
T:new() 无参数构造函数约束保证T必须有无参数构造函数
T:<基类名>    基类约束时,基类不能是密封类,即不能是sealed类。sealed类表示该类不能被继承,在这里用作约束就无任何意义,因为sealed类没有子类。
T:<接口名称>  接口约束保证T必须实现接口

泛型约束可以同时约束多个。

如:where T : People, ISports  要求T必须是People或People的子类,或同时实现ISports接口。

四、泛型的协变和逆变

协变和逆变是在.NET 4.0的时候出现的,只能放在接口或者委托的泛型参数前面。
out :协变(covariant),用来修饰返回值;
in:逆变(contravariant),用来修饰传入参数。

C#类型转换发生在单一类型中,如:小范围类型的int隐式转换成大范围类型long,大范围类型long强制转换成小范围类型int。而泛型的协变,发生在泛型中。

泛型不是单一类型。如:List<T>  List是数据类型,T也是数据类型。

泛型可以认为是复合类型。

协变:类似于隐式类型转换,但有所不同。协变控制的是返回值的类型。如:public interface IEnumerable<out T>

逆变:类似于强制类型转换,但有所不同。逆变控制的是传入参数的类型。如:public delegate bool Predicate<in T>(T obj)

协变和逆变只能放在接口或者委托的泛型参数前面,类型转换没有此限制。

使用了协变以后,=左边声明的是基类,右边可以声明基类或者基类的子类。简单理解:即小转大。
如:协变
IEnumerable<Bird> birdList1 = new List<Bird>();
IEnumerable<Bird> birdList2 = new List<Sparrow>();

使用了逆变之后,=左边声明是子类,右边可以声明子类或者子类的基类。简单理解:即大转小。
 

标签:Console,C#,GetType,接口,概括,WriteLine,类型,泛型
From: https://blog.csdn.net/2302_77639120/article/details/141085995

相关文章

  • 初始化二维vector
    这里是我遇到的一些对于二维vector容器初始化的一些问题的总结与记录,一共有一下四种情况,随时添加新的方式方法。初始化一个二维vector,行M,列N//初始化一个二维的matrix,行M,列N,且值为0vector<vector<int>>matrix(M,vector<int>(N));//等价于下面的vector<vector<......
  • [rCore学习笔记 024]多道程序与协作式调度
    写在前面本随笔是非常菜的菜鸡写的。如有问题请及时提出。可以联系:[email protected]:https://github.com/WindDevil(目前啥也没有本节重点主要是对 任务 的概念进行进一步扩展和延伸:形成任务运行状态:任务从开始到结束执行过程中所处的不同运行状态:未初始化、准备......
  • CF1863E Speedrun 题解
    CF1863E你在玩一个游戏,要完成\(n\)个任务。其中对于每个任务\(i\),它只能在某一天的第\(h_i\)时刻完成。游戏每天有\(k\)个小时,分别编号为\(0,1,...k-1\)。给出\(m\)对任务间的依赖关系,\((a_i,b_i)\)表示\(a_i\)必须比\(b_i\)先完成。保证依赖关系不形成环。完......
  • P2014 [CTSC1997] 选课
    原题链接题解解法一:三维dp,dp[root][j][k]含义,以root为根结点的树中只在前j棵子树中选k门课程的最大学分。code #include<bits/stdc++.h>usingnamespacestd;intn,m;intval[305],num[305];intdp[305][305][305];vector<vector<int>>G(302);intf(......
  • Python类中__del__()、__call__()、__repr__()、__new__()、__hash__()方法
    1.__del__()销毁魔术方法触发时机:当一个对象在内存中被销毁的时候自动执行参数:至少有一个self,接收对象返回值:无作用:在对象销毁的时候做一些操作注意:程序自动调用此方法,不需要我们手动调用。classCat:def__init__(self,name):print("--init--")s......
  • C-10-快速语法参考-全-
    C#10快速语法参考(全)原文:C#10QuickSyntaxReference协议:CCBY-NC-SA4.0一、你好世界选择IDE要开始用C#编码,你需要一个支持.NET的集成开发环境(IDE),最流行的选择是微软自己的VisualStudio。122自2002年C#1.0首次发布以来,C#语言经历了多次更新。在撰写本......
  • HashMap 中处理哈希冲突,红黑树对于没有实现 Comparable 接口的 Key 处理
    背景:假设有两个对象,分别是stu和teach(都没有实现Comparable接口),将它们添加进去HashMap里,假设这两个对象发生哈希冲突,那么红黑树怎么判断它们谁在左谁在右?依据是什么?​ 当两个对象stu和teach的哈希值相同,且它们没有实现Comparable接口时,Java8的HashMap会使用t......
  • C--编程零基础入门指南-全-
    C#编程零基础入门指南(全)原文:C#ProgrammingforAbsoluteBeginners协议:CCBY-NC-SA4.0一、做好准备亲爱的读者,欢迎您开始学习编程之旅!电脑、平板电脑、手机和许多其他电子设备都是可编程的,会完全按照人类程序员告诉他们的去做。编程是一个完全基于逻辑的世界。在这方面,......
  • smbmap报[*] Detected 0 hosts serving SMB
    执行smbmapsmbmap-H{target_ip}显示[*]Detected0hostsservingSMB[*]Closed0connectionsvps连目标机时正常,vps距离目标时延较低抓包显示本机直接syn, syn+ack,第三个包直接rst怀疑是timeout设置问题查看帮助mansmbmap发现可以设置--timeout,默认0.5s......
  • 探索-C--高级特性-全-
    探索C#高级特性(全)原文:ExploringAdvancedFeaturesinC#协议:CCBY-NC-SA4.0一、受关注的C#7C#7于2017年3月发布,是VisualStudio2017发布的一部分。如上所述。NETBlog中,C#7专注于数据消费、简化代码和提高性能。C#7最大的特点是元组和模式匹配。使用元......