C#泛型详解及关键字作用

作者:黄厚镇 时间:2023-04-07 20:23:12 

这篇文章主要来讲讲c#中的泛型,因为泛型在c#中有很重要的位置,对于写出高可读性,高性能的代码有着关键的作用。

一、什么是泛型?

泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个非常重要的新功能。

我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。但我们没有办法,只能分别写多个方法来处理不同的数据类型。这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的,可以看出,微软还是很贴心的。

二、为什么要使用泛型?

接下来我们来看一段代码。


public class GenericClass
   {
       public void ShowInt(int n)
       {
           Console.WriteLine("ShowInt print {0},ShowInt Parament Type Is {1}",n,n.GetType());
       }
       public void ShowDateTime(DateTime dt)
       {
           Console.WriteLine("ShowDateTime print {0},ShowDateTime Parament Type Is {1}", dt, dt.GetType());
       }
       public void ShowPeople(People people)
       {
           Console.WriteLine("ShowPeople print {0},ShowPeople Parament Type Is {1}", people, people.GetType());
       }
   }

static void Main(string[] args)
       {
           GenericClass generice = new GenericClass();
           generice.ShowInt(11);
           generice.ShowDateTime(DateTime.Now);
           generice.ShowPeople(new People { Id = 11, Name = "Tom" });

Console.ReadKey();
       }

显示结果:

C#泛型详解及关键字作用

我们可以看出这三个方法,除了传入的参数不同外,其里面实现的功能都是一样的。在1.1版的时候,还没有泛型这个概念,那么怎么办呢。就有人想到了OOP三大特性之一的继承,我们知道,C#语言中,object是所有类型的基类,将上面的代码进行以下优化:


public class GenericClass
   {
       public void ShowObj(object obj)
       {
           Console.WriteLine("ShowObj print {0},ShowObj Parament Type Is {1}", obj, obj.GetType());
       }
   }
       static void Main(string[] args)
       {
           Console.WriteLine("*****************object调用*********************");
           generice.ShowObj(11);
           generice.ShowObj(DateTime.Now);
           generice.ShowObj(new People { Id = 11, Name = "Tom" });

Console.ReadKey();
       }

显示结果:

C#泛型详解及关键字作用

我们可以看出,目地是达到了。解决了代码的可读性,但是这样又有个不好的地方了,我们这样做实际上是一个装箱拆箱操作,会损耗性能。

终于,微软在2.0的时候发布了泛型。接下来我们用泛型方法来实现该功能。

三、泛型类型参数

在使用泛型方法之前,我们先来了解下有关于泛型的一些知识。

在泛型类型或方法定义中,类型参数是在其实例化泛型类型的一个变量时,客户端指定的特定类型的占位符。 泛型类(GenericList<T>)无法按原样使用,因为它不是真正的类型;它更像是类型的蓝图。 若要使用GenericList<T>,客户端代码必须通过指定尖括号内的类型参数来声明并实例化构造类型。 此特定类的类型参数可以是编译器可识别的任何类型。 可创建任意数量的构造类型实例,其中每个使用不同的类型参数,如下所示:


GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();

GenericList<T>的每个实例中,类中出现的每个T在运行时均会被替换为类型参数。 通过这种替换,我们已通过使用单个类定义创建了三个单独的类型安全的有效对象。

三、泛型约束

定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的几种类型施加限制。 如果客户端代码尝试使用约束所不允许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。 通过使用where上下文关键字指定约束。 下表列出了六种类型的约束:

C#泛型详解及关键字作用

where T:结构(类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。)


class MyClass<U>
       where U : struct///约束U参数必须为“值 类型”
{ }

public void MyMetod<T>(T t)
      where T : struct
{          
}

where T:类(类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。)


class MyClass<U>
       where U : class///约束U参数必须为“引用类型”
{ }

public void MyMetod<T>(T t)
      where T : class
{          
}

where T:new()(类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。)


class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
   // ...
}

where T:<基类名>(类型参数必须是指定的基类或派生自指定的基类。)


public class Employee{}

public class GenericList<T> where T : Employee

where T:<接口名称>(类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。)


/// <summary>
   /// 接口
   /// </summary>
   interface IMyInterface
   {
   }

/// <summary>
   /// 定义的一个字典类型
   /// </summary>
   /// <typeparam name="TKey"></typeparam>
   /// <typeparam name="TVal"></typeparam>
   class Dictionary<TKey, TVal>
       where TKey : IComparable, IEnumerable
       where TVal : IMyInterface
   {
       public void Add(TKey key, TVal val)
       {
       }
   }

where T:U(为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。也就是说T和U的参数必须一样)


class List<T>
{
   void Add<U>(List<U> items) where U : T {/*...*/}
}

来源:https://www.cnblogs.com/hhzblogs/p/7820005.html

标签:C#,泛型
0
投稿

猜你喜欢

  • Java中的static关键字你了解多少

    2022-05-21 11:25:51
  • Android Studio 引用外部依赖时报错的解决方法

    2023-09-26 18:20:11
  • 在mybatis 中使用if else 进行判断的操作

    2021-11-10 23:17:11
  • File.createTempFile创建临时文件的示例详解

    2022-05-03 08:52:41
  • Feign调用可重试的最佳方案分享

    2021-06-09 12:19:23
  • C#隐藏控制台键盘输入的方法

    2022-04-29 21:11:06
  • 一个简单的Spring容器初始化流程详解

    2023-11-13 02:10:55
  • 字符串阵列String[]转换为整型阵列Int[]的实例

    2021-07-22 08:19:17
  • 1小时快速上手RabbitMQ(简介及安装过程)

    2022-04-26 15:49:40
  • Spring零基础入门WebFlux响应式编程

    2022-07-12 07:25:53
  • java压缩zip文件中文乱码问题解决方法

    2022-12-20 11:14:25
  • Java KeyGenerator.generateKey的19个方法代码示例

    2022-08-08 14:26:40
  • java面试try-with-resources问题解答

    2023-09-03 15:08:01
  • springboot+mybatis报错找不到实体类的问题

    2023-05-20 02:04:10
  • java多线程抓取铃声多多官网的铃声数据

    2023-12-18 23:20:05
  • Android layoutAnimation详解及应用

    2022-11-01 11:15:07
  • springboot基于docsify 实现随身文档

    2023-04-25 04:52:23
  • java 过滤器filter防sql注入的实现代码

    2023-08-30 09:56:40
  • MyBatisPlus+Lombok实现分页功能的方法详解

    2021-07-04 06:34:57
  • IDEA使用SequenceDiagram插件绘制时序图的方法

    2023-07-03 11:20:07
  • asp之家 软件编程 m.aspxhome.com