泛型

感谢腾讯课堂软谋教育的Eleven老师对于泛型的详细讲解。

PS:如有不足之处,还望大家多多指教,万分感谢。

泛型概念  

泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现

泛型类和泛型方法兼复用性、类型安全和高效率于一身,是与之对应的非泛型的类和方法所不及。泛型广泛用于容器(collections)和对容器操作的方法中。.NET框架2.0的类库提供一个新的命名空间System.Collections.Generic,其中包含了一些新的基于泛型的容器类。要查找新的泛型容器类(collection classes)的示例代码,请参见基础类库中的泛型。当然,你也可以创建自己的泛型类和方法,以提供你自己的泛化的方案和设计模式,这是类型安全且高效的。

 

泛型的声明和使用

泛型类的定义

 

   访问修饰符 class ClassName<T>{}

   示例:public class GenericClass<T>{}

泛型方法的定义

   访问修饰符 返回值类型 methodName(参数类型/参数类型列表){}

   示例: 

    publice T GenericMethod<T,M>(){}//声明一个带返回值(泛型)的方法,有N个泛型参数

    调用时需要注意:必须指定类型参数(泛型方法可以不知道是什么类型,但是调用者必须知道是什么类型)

    .GenericMethod<int,string>(tempInt,tempString);//必须和声明时的个数保持一致,<>里的类型和()的参数的类型必须是一致。

泛型接口的定义

    申明接口的关键字  interfaceName<T.....>{ 返回值类型 methodName(参数类型 参数名称);}

    interface interfaceName<T>{ void method(T s1)}//这里举例用泛型

   继承

    类:接口名称<这里需要指定具体类型>//例如string.....

    Class :interfaceName<string>//快捷实现接口的method方法

    publice void method<T>(T s1){//方法体}

   调用

   实例化Class.method<string>("嘿嘿");//调用时必须指定类型和具体值.

泛型委托的定义

   访问修饰符 delegate 返回类型 delegateName<T>(T t1......);//这里用返回值(泛型)、带参数(泛型)举例

   public delegate T DelegateName<T>(T t1);//声明委托,这里用返回值(泛型)、带参数(泛型)举例

   //定义委托方法

    publice T tempMethod<T>(T t1){ return  t1;}//这里省略,只是简单返回值

  //在方法内部实例化委托

   {

    //语法糖,可以把原来的=new DelegateNmae<string>(tempMethod<string>)省略

    DelegateName<string> tempName=tempMethod<string>;//实例化委托的时候必须给定具体类型

     tempName.Invoke("测试");//传递具体参数    

}

 

类型参数的约束

 

    为什么要有约束?  因为有约束才有权利   

 

约束使得泛型类能够使用其他实例的属性,因为所有为类型T的元素,都是一个对象或是一个继承自Employee的对象。

public class Employee
{
 public class Employee
    {
        private string name;
        private int id;
        public Employee(string s, int i)
        {
            name = s;
            id = i;
        }
 
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public int ID
        {
            get { return id; }
            set { id = value; }
        }
 
    }
}

 

class MyList<T> where T: Employee
{
 //Rest of class as before.
  public T FindFirstOccurrence(string s)
  {
   T t = null;
   Reset();
   while (HasItems())
   {
      if (current != null)
      {
//The constraint enables this:
         if (current.Data.Name == s)
         {
            t = current.Data;
            break;
         }
         else
         {
            current = current.Next;
         }
      } //end if
   } // end while
  return t;
  }
}
 

 

泛型约束的几种常见类型:

约束

描述

where T: struct

类型参数必须为值类型。

where T : class

类型参数必须为引用类型。

where T : new()

类型参数必须有一个公有、无参的构造函数。当于其它约束联合使用时,new()约束必须放在最后。

where T : <base class name>

类型参数必须是指定的基类型或是派生自指定的基类型。

where T : <interface name>

类型参数必须是指定的接口或是指定接口的实现。可以指定多个接口约束。接口约束也可以是泛型的。

 

 

针对早期版本的通用语言运行时和C#语言的局限,泛型提供了一个解决方案。以前类型的泛化(generalization)是靠类型与全局基类System.Object的相互转换来实现。.NET框架基础类库的ArrayList容器类,就是这种局限的一个例子。ArrayList是一个很方便的容器类,使用中无需更改就可以存储任何引用类型或值类型。

 

 

//The .NET Framework 1.1 way of creating a list
ArrayList list1 = new ArrayList(); 
list1.Add(3);
list1.Add(105);
//...
ArrayList list2 = new ArrayList();
list2.Add(“It is raining in Redmond.”);
list2.Add("It is snowing in the mountains.");
//...

 

但是这种便利是有代价的,这需要把任何一个加入ArrayList的引用类型或值类型都隐式地向上转换成System.Object。如果这些元素是值类型,那么当加入到列表中时,它们必须被装箱;当重新取回它们时,要拆箱。类型转换和装箱、拆箱的操作都降低了性能;在必须迭代(iterate)大容器的情况下,装箱和拆箱的影响可能十分显著。

另一个局限是缺乏编译时的类型检查,当一个ArrayList把任何类型都转换为Object,就无法在编译时预防客户代码类似这样的操作:

 

 

ArrayList list = new ArrayList(); 
//Okay.  
list.Add(3); 
//Okay, but did you really want to do this?
list.Add(.“It is raining in Redmond.”);
 
int t = 0;
//This causes an InvalidCastException to be returned.
    foreach(int x in list)
{
  t += x;
}

 

下面的示例代码以一个简单的泛型链表类作为示范。(多数情况下,推荐使用由.NET框架类库提供的List<T>类,而不是创建自己的表。)类型参数T在多处使用,具体类型通常在这些地方来指明表中元素的类型。类型参数T有以下几种用法:

        AddHead方法中,作为方法参数的类型。

        在公共方法GetNext中,以及嵌套类NodeData属性中作为返回值的类型。

        在嵌套类中,作为私有成员data的类型。

 

注意一点,T对嵌套的类Node也是有效的。当用一个具体类来实现MyList<T>——MyList<int>——每个出现过的T都要用int代替。

 

using System;
using System.Collections.Generic;
 
public class MyList<T> //type parameter T in angle brackets
    {
        private Node head;
// The nested type is also generic on T.
        private class Node          
        {
            private Node next;
//T as private member data type:
            private T data;         
//T used in non-generic constructor:
            public Node(T t)        
            {
                next = null;
                data = t;
            }
            public Node Next
            {
                get { return next; }
                set { next = value; }
            }
        //T as return type of property:
            public T Data           
            {
                get { return data; }
                set { data = value; }
            }
        }
        public MyList()
        {
            head = null;
        }
     //T as method parameter type:
        public void AddHead(T t)    
        {
            Node n = new Node(t);
            n.Next = head;
            head = n;
        }
        public IEnumerator<T> GetEnumerator()
        {
            Node current = head;
 
            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }
        }
    }

下面的示例代码演示了客户代码如何使用泛型类MyList<T>,来创建一个整数表。通过简单地改变参数的类型,很容易改写下面的代码,以创建字符串或其他自定义类型的表。

 

class Program
    {
        static void Main(string[] args)
        {
//int is the type argument.
           MyList<int> list = new MyList<int>();
            for (int x = 0; x < 10; x++)
                list.AddHead(x);
 
            foreach (int i in list)
            {
                Console.WriteLine(i);
            }
            Console.WriteLine("Done");
        }
    }


 

转载于:https://www.cnblogs.com/JohnTang/p/10906974.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值