• 泛型集合和ArrayList的装箱拆箱、常见的泛型类型、泛型类和泛型方法、泛型约束、 泛型委托泛型很难理解?不然在接触的一个新的概念的时候,总会感觉难以理解,当你掌握并能熟练地使用的时候,发现这个概念其实简单...
    前文传送门,dotNET开发基础汇总系列
    [StackOverflow 20万阅读的问题:如何实现异步Task超时的处理](https://blog.csdn.net/kebi007/article/details/103849080)
    [Func和Action委托简单用法](https://blog.csdn.net/kebi007/article/details/69367562)
    [C#异步编程基础入门总结](https://blog.csdn.net/kebi007/article/details/76899078)
    [C#泛型入门学习泛型类、泛型集合、泛型方法、泛型约束、泛型委托](https://blog.csdn.net/kebi007/article/details/77800954)
    [C#异常处理总结](https://blog.csdn.net/kebi007/article/details/78221083)
    
    ###本章阅读列表###
    
     - 泛型很难理解?不然
     - 泛型集合和ArrayList的装箱拆箱
     - 常见的泛型类型
     - 泛型类和泛型方法
     - 泛型约束
     - 泛型委托
     
     
     ###泛型很难理解?不然 ###
     在接触的一个新的概念的时候,总会感觉难以理解,当你掌握并能熟练地使用的时候,发现这个概念其实简单的,我相信大多数码农都会有这种似曾相识的感觉。可能大多数人刚学习泛型的时候觉得很难理解,当然我也是这样的,所以便写下这篇文章加深一下对泛型的印象。
     第一次接触泛型那还是在大二上学期的时候,那会是学c#面向对象的时候接触过泛型集合,但尴尬的是那会还没有“泛型”这个概念,仅仅只停留在泛型集合的使用。关于泛型入门的文章csdn和博客园有很多,这里我也写一篇关于我对泛型学习的一个总结,如果出现错误表达不当的地方,还希望评论指出。
     ###泛型优点###
    官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/introduction-to-generics
    简介:
     泛型是.NET Framework2.0新增的一个特性,在命名空间System.Collections.Generic,包含了几个新的基于泛型的集合类,官方建议.net 2.0 及更高版本的应用程序使用心得泛型集合类,而不使用非泛型集合类,例如ArrayList。
     官方解释:
     泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
    泛型的定义主要有以下两种:
    1.在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)
    2.在程序编码中一些包含参数的类。其参数可以代表类或对象等等。(人们大多把这称作模板)不论使用哪个定义,泛型的参数在真正使用泛型时都必须作出指明
     官方的解释虽然很难理解,用我的话来解释那就是,声明类和方法时一般都需要定义是什么类,class Brid ,Class Food...... 声明泛型类和方法时只需要传入类型的地方用 ,有点类似于占位符的作用,用的时候传入具体的类型。当针对不同类型具有相同行为的时候,也就是泛型发挥作用的时候。
     优点:
     1.使用泛型类、方法,我们可以极大提高代码的重用性,不需要对类型不同代码相同(仅类型参数不同)的代码写多次。
     2.创建泛型类,可在编译时创建类型安全的集合
     3.避免装箱和拆箱操作降低性能,在大型集合中装箱和拆箱的影响非常大. 
    ### 泛型集合和ArrayList的装箱拆箱###
    装箱:是指从值类型转换成引用类型
    拆箱:是指从引用类型转换成值类型
    下面的例子是借鉴官方的一段代码:
    
    ```
        System.Collections.ArrayList list1 = new System.Collections.ArrayList();
                list1.Add(3);
                list1.Add(105);
    
                System.Collections.ArrayList list2 = new System.Collections.ArrayList();
                list2.Add("科比");
                list2.Add("詹姆斯");
    ```
    ArrayList是一个极为方便的集合类,可以用于存储任何引用或值类型。但是缺点也很明显,第一个缺点是编译的时候不会检查类型,例如
    
    ```
      System.Collections.ArrayList list1 = new System.Collections.ArrayList();
                list1.Add(3);
                list1.Add(105);
                list1.Add("sd");
                foreach (int item in list1)
                {
                    Console.WriteLine(item.ToString());
                }
    ```
    编译正常,运行的时候会出现转换类型错误。
     至于ArrayList第二个缺点就是装箱拆箱的时候回造成性能的损失。我们看看ArrayList的Add方法的定义。
     ![这里写图片描述](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTI1MTUxOTA0Mjc2)
     参数是一个object类型,也就是说ArrayList添加任何引用类型或值类型都会隐士转换成Object,这个时候便发生装箱操作,在遍历检索它们时必须从object 类型转换成指定的类型,这个时候便发生拆箱操作。这两种操作会大大降低性能。所以.net 2.0的程序时应该放弃使用ArrayList,推荐使用使用List《T》 泛型集合。这也是我们为什么要使用泛型的原因之一。
     
    ###常见的泛型类型###
    在泛型类型的定义中,出现的每个T(一个展位变量而已叫别的名字也行)在运行时都会被替换成实际的类型参数。下面是一些基础的泛型类型
    1.泛型类
    ```
               class MyGenericClass
            {
              //......
            }
    ```
    2.泛型接口
    ```
            interface  GenericInterface
            {
               void  GenericMethod(T t);
            }
    ```
    3.泛型方法
    ```
            public void MyGenericMethod()
            {
              //......
            }
    ```
    4.泛型数组
    
    ```
    public T[] GenericArray;
    ```
    5.泛型委托
    
    ```
     public delegate TOutput GenericDelagete(TInput input);
    ```
    
    6.泛型结构
    
    ```
       struct MyGenericStruct
            {
    
            }
    ```
    在使用时所有的T的都要替换成具体的类型。
    类型参数命名指南,参见官方文档
    ![这里写图片描述](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTI1MTYyMjM0MzUz)
    ###泛型类和泛型方法###
    我们先来看看泛型方法,这个方法的用途是来交换两个变量的
    
    ```
            static void Main(string[] args)
            {
                int a = 1;
                int b = 2;
                SwapInt(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            public static void SwapInt(ref int a, ref int b)
            {
                int temp;
                temp = a;
                a = b;
                b = temp;
            }
    ```
    结果是a=2,b=1,但是我们现在要换成string类型呢,是不是得再写一个string参数的方法呢,如果是char、double...........,这每个不同类型的参数都要写一个参数,的确太麻烦并且没有这个必要,Object ?当然可以
    
    ```
            static void Main(string[] args)
            {
                object a = 1;
                object b = 2;
                SwapObject(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            public static void SwapObject(ref object a, ref object b)
            {
                object temp;
                temp = a;
                a = b;
                b = temp;
            }
    ```
    这确实能解决代码复用的需求,但是上面我们已经知道使用Object类型会发生装箱拆箱的操作,会降低性能。所以我们可以使用泛型方法解决这个缺点。
    
    ```
        static void Main(string[] args)
            {
                int a = 1;
                int b = 2;
                SwapGeneric(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            //交换两个变量的方法
            public static void SwapGeneric(ref T a, ref T b)
            {
                T temp;
                temp = a;
                a = b;
                b = temp;
            }
    ```
    泛型类:这个泛型类常用api通用接口的泛型类。
    
    ```
        class Program
        {
            static void Main(string[] args)
            {
                List data = new List() {
                                  new Client.Product() { Id=12,Name="土豆"},
                                  new Client.Product() { Id=12,Name="茄子"},
                                  new Client.Product() { Id=12,Name="黄瓜"}
               };
               var resultProduct = Result.Success(data);
                var resultUser = Result.Error("没有数据");
                foreach (var item in resultProduct.Data)
                {
                    Console.WriteLine(item.Id+","+item.Name);
                }
                Console.WriteLine(resultUser.IsSuccess+resultUser.Message);
            }
    
        }
        public class Result { //泛型类,声明T变量类型
            public bool IsSuccess { get; set; }
            public List Data { get; set;}//未定义具体类型的泛型集合
            public string Message { get; set; }
            public static Result Error(string message) 
            {
                return new Client.Result { IsSuccess = false, Message = message };
            }
            //泛型方法,初始化数据
            public static Result Success(List data)
            {
                return new Client.Result { IsSuccess =true,Data =data}; //成功就没有提示消息的原则
            }
        }
        public class Product {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class User {
            public int Age { get; set; }
            public string Name { get; set; }
        }
    ```
    使用该通用的泛型类的好处在于,获取不同的对象集合不需要写多个方法,获取Product数据集合、获取User数据集.........。只需要调用Success方法既可,使代码变得可复用。
    ###泛型类型参数约束###
    为什么要使用类型参数的约束呢,简单点说就是筛选类型参数,在使用泛型的代码中如果违反了某个约束不允许的类型来实例化则会产生编译错误,类型参数的约束是使用关键字where。 下面列出了6中类型的约束
    
     1. where T: struct
    类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可以为 null 的类型(C# 编程指南)。
     2. where T : class
    类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
     3. where T:new()
    类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
     4. where T:
    类型参数必须是指定的基类或派生自指定的基类。
     5. where T:
    类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
    6. where T:U
    为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。
    我们在看看上面那个交换两个变量的方法SwapGeneric,加上必须是值类型的约束
    
    ```
      public static void SwapGeneric(ref T a,ref T b) where T :struct 
            {
                T temp;
                temp = a;
                a = b;
                b = a;
            }
            //实例化
                Product p = new Product() { Id=1,Name="土豆"};
                Product p1 = new Product() { Id=2,Name ="茄子"};
                SwapGeneric(ref p,ref p1);
    ```
    我们在使用的时候编译给我们提示了以下的错误:
    ![这里写图片描述](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTI1MTgxNjIyNDk3)
    “类型Product必须是不可以为NUll值得类型”,引用类型的默认值就是NULL,所以该房型方法的类型参数不能是引用类型,这就是使用类型参数约束的好处。
    **约束多个参数**
    
    ```
        class List where TLive:User where U:struct
        {
    
        }
    ```
    ###泛型委托###
    泛型委托可以自己定义自己的类型参数,声明的时候还是和泛型类、泛型方法一样加个 站个坑,其实泛型委托使用的时候不是很多,要慎用。,如以下事例
    
    ```
    public delegate T DelegateGeneric(T item);
    DelegateGeneric test = StringMethod;
            public static string StringMethod(string name)
            {
                return "你好" + name;
            }
    ```
    将上面的交换两个变量的方法改成委托是这样的
    
    ```
            public delegate void DelegateGenericSwap(ref T a,ref T b);
                string a = "张林";
                string b = "科比";
                DelegateGenericSwap swap = GenericSwap;
                Console.WriteLine($"a:{a}b:{b}");
               public static void GenericSwap(ref T a,ref T b)
            {
                T temp;
                temp = a;
                a = b;
                b = a;
            }
    ```
    > **作者信息**:
    【文章信息】:作者-张林:原文链接-https://blog.csdn.net/kebi007/article/details/77800954
    【原创公众号】:dotNet全栈开发。[好文目录](https://mp.weixin.qq.com/s/PXnpK4E1rB261UqzmcfpVw)
    版权声明:本文为CSDN博主「dotNet全栈开发」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    
    展开全文
  • C#数组、ArrayList和List三者的区别 在C#数组,ArrayList,List都能够存储一组对象,那么这三者到底有什么样的区别呢。 数组  数组C#中最早出现的。在内存中是连续存储的,所以它的索引速度非常快,而且...
  • 转载自:C#泛型约束where是什么泛型约束: 确保泛型类使用的参数是提供特定方法的类型。 详见:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/generic-classes 约束说明T:结构类型...
  • C#泛型  泛型(使用System.Collections.Generic命名空间)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters:不必确定一个或多个具体参数,属于同一类即可。这就...
  • C# 泛型约束List<T> (转) 2019-06-25 12:21:51
    所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。 在定义泛型类时,可以对客户端代码能够在实例化类时用于...
  • 首先,来看一个程序,对泛型有一个初步的认识。 namespace ConsoleApplication { class GenericDemo { public static void Test() { double[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  • C# 泛型方法Where 约束 2018-01-19 10:24:58
    where(泛型类型约束)定义:在定义泛型的时候,我们可以使用 where 限制参数的范围。使用:在使用泛型的时候,你必须尊守 where 限制参数的范围,否则编译不会通过。 六种类型约束:T:类(类型参数必须是...
  • C#中的泛型约束 2017-06-06 11:35:11
    使用约束的原因如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是...
  • C#泛型参数的约束 2019-06-27 19:45:12
    在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束约束是使用 where 上下文...
  • c# where(泛型类型约束 2019-08-06 22:50:35
    c# where(泛型类型约束) 原文:c# where(泛型类型约束)定义:在定义泛型的时候,我们可以使用where限制参数的范围。 使用:在使用泛型的时候,你必须尊守where限制参数的范围,否则编译不会通过。...
  • C# 泛型约束 2019-10-25 15:27:58
    约束告知编译器类型参数必须具备的功能。在没有任何约束的情况下,类型参数可以是任何类型。编译器只能假定System.Object的成员,它是任何 .NET 类型的最终基类。有关详细信息,请参阅使用约束的原因。如果客户端...
  • 泛型及泛型约束-小结 2018-03-07 19:07:32
    8.泛型 泛型约束 泛型:作用是“代码重用”,用于“算法重用”。CLR允许创建泛型引用类型和泛型值类型,但不允许创建泛型枚举类型,还可以创建泛型接口和泛型委托。 原则:泛型参数变量为T,或者以T开头(如TKey ...
  • 在一本书中看到 ”主约束“ 一词,比较生疏。百度了一下,竟然没找到解释,经过测试,终于搞懂了。既然如此,那我就就此写一篇,希望能帮助到遇到同样困惑的筒子们。  参数约束主要有六种:(下表摘自 MSDN 的...
  • 来自Hauk的文章C# 泛型编程之泛型类、泛型方法、泛型约束    所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型。  泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活...
  • C#泛型和泛型约束 2019-08-09 23:11:52
    一、泛型:  所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型。...二、泛型约束:  转自:http://www.cnblogs.com/kk888/archive/2011/09/01/2161647.html 在定义泛型类时,可以对客户端代码...
  • //1: //先定义2个属性存书名书编号,这里有2中属性的使用方式=-=  private int id; private string name; public int Id { get{return id ;} set { id = value; } } publi
  • C# 泛型类型参数的约束在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束约束...
  • C# 泛型约束,泛型函数 2010-11-17 20:35:00
    class 泛型 { public static void Main() { //---------------测试泛型约束------- //定义一个Pression数组 Pression[] pr = new Pression[] { new Pression("蚊
1 2 3 4 5 ... 20
收藏数 4,912
精华内容 1,964