C#学习笔记(五):泛型

认识泛型

泛型使类型参数化,从而实现了算法上的代码重用。

同时由于去掉了转换中装箱和拆箱的操作,使用泛型还可以提高程序的运行速度。

我们先看看C#自带的使用了泛型的类:

 1 using System.Collections.Generic;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             List<int> list1 = new List<int>();
10             list1.Add(100);
11             int i = list1[0];
12
13             List<string> list2 = new List<string>();
14             list2.Add("Hello");
15             string s = list2[0];
16         }
17     }
18 }

通过使用泛型,我们可以重复利用List提供的功能,而不用每个类型对应去写一个List的类。

泛型在类上的实现

下面我们自己使用泛型编写一个简单的类,如下:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Test<int> test1 = new Test<int>();
10             test1.myValue = 100;
11             Console.WriteLine(test1.myValue);
12
13             Test<string> test2 = new Test<string>();
14             test2.myValue = "Hello";
15             Console.WriteLine(test2.myValue);
16         }
17     }
18
19     public class Test<T>
20     {
21         private T _myValue;
22
23         public T myValue
24         {
25             set { _myValue = value; }
26             get { return _myValue; }
27         }
28     }
29 }

Test类中的尖括号里面的T即为泛型,其可以表示任意的类型。

泛型约束

我们上面示例中的T可以使用任意的类型,那么如果我们只希望T是某类型或某类型的子类该怎么办呢?

public class Test<T> where T : IComparable

如果这样写,则表示T必须是实现了IComparable接口的对象。

多个类型的情况

多个类型的写法如下:

public class Test<T, K> where T : IComparable where K : ICloneable

如上所示,一个类型如果要添加约束就需要写一个where进行对应,所以有多个就会有多个where关键字出现。

创建类型的情况

如果需要使用new创建一个类型,则需要在约束里添加new()的字符串,如下:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Test<Data> test1 = new Test<Data>();
10             Console.WriteLine(test1.myComparable.s);
11
12             Console.Read();
13         }
14     }
15
16     public class Test<T> where T : IComparable, new()
17     {
18         private T _myComparable;
19
20         public T myComparable
21         {
22             set { _myComparable = value; }
23             get { return _myComparable; }
24         }
25
26         public Test()
27         {
28             _myComparable = new T();
29         }
30     }
31
32     public class Data : IComparable
33     {
34         public string s = "Hello World!";
35
36         public int CompareTo(object obj)
37         {
38             return 0;
39         }
40     }
41 }

但是如果是值类型,则不需要这么写,但是要约束T为值类型,如下:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Test<int> test1 = new Test<int>();
10             Console.WriteLine(test1.myComparable);
11
12             Console.Read();
13         }
14     }
15
16     public class Test<T> where T : struct
17     {
18         private T _myComparable;
19
20         public T myComparable
21         {
22             set { _myComparable = value; }
23             get { return _myComparable; }
24         }
25
26         public Test()
27         {
28             _myComparable = new T();
29         }
30     }
31 }

default关键字

当我们需要对泛型T置空时不能直接写“xxx=null;”因为只有当 T 为引用类型时,语句 t = null 才有效;只有当 T 为数值类型而不是结构时,语句 t = 0 才能正常使用。所以我们使用default关键字就可以解决这个问题,如下:

_myComparable = default(T);

泛型继承

子类也有相同的泛型时:

1 public class A<T>
2 { }
3
4 public class B<T> : A<T>
5 { }

当然,你可以使用另外的名称,只要能对应上即可:

1 public class A<T>
2 { }
3
4 public class B<K> : A<K>
5 { }

子类指定好类型:

1 public class A<T>
2 { }
3
4 public class B : A<string>
5 { }

子类添加新类型:

1 public class A<T>
2 { }
3
4 public class B<T, K> : A<T>
5 { }

泛型在方法上的实现

如果要在方法上添加类上没有指定的类型,可以直接在方法上添加泛型:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Test<int> test = new Test<int>();
10             Console.WriteLine(test.Func<string>("Hello"));
11
12             Console.Read();
13         }
14     }
15
16     public class Test<T>
17     {
18         public K Func<K>(K k)
19         {
20             return k;
21         }
22     }
23 }

泛型在委托上的实现

委托上也可以使用泛型,定义方法和在方法上使用泛型一致,如下:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             new Test();
10
11             Console.Read();
12         }
13     }
14
15     public class Test
16     {
17         public delegate T add<T>(T a, T b);
18
19         public Test()
20         {
21             add<int> func1 = AddInt;
22             Console.WriteLine(func1(100, 23));
23
24             add<float> func2 = AddFloat;
25             Console.WriteLine(func2(1.2f, 0.03f));
26         }
27
28         private int AddInt(int a, int b)
29         {
30             return a + b;
31         }
32
33         private float AddFloat(float a, float b)
34         {
35             return a + b;
36         }
37     }
38 }

泛型接口

泛型接口的使用和泛型类一致,大家可以查看微软自己的文档:https://msdn.microsoft.com/zh-cn/library/kwtft8ak(VS.80).aspx

泛型和静态字段与方法

泛型同样可以使用在静态字段和方法中,由于静态字段和方法在内存中始终只存在一个,所以当我们使用了泛型的时候,编译器会帮我们自动生成对应的方法。

泛型静态的使用和动态一致就跳过不说了。

类型推断

我们在调用泛型方法时可以省略泛型类型的书写,完全交由编译器根据我们的类型来进行判断,这样可以减小代码量同时也更清晰:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             //没有类型推断
10             Console.WriteLine(CompareTo<int>(100, 100));
11
12             //使用类型推断
13             Console.WriteLine(CompareTo(12.3f, 12.33f));
14             Console.WriteLine(CompareTo(‘a‘, ‘a‘));
15
16             Console.Read();
17         }
18
19         private static int CompareTo<T>(T a, T b) where T : IComparable
20         {
21             return a.CompareTo(b);
22         }
23     }
24 }
时间: 07-04

C#学习笔记(五):泛型的相关文章

Caliburn.Micro学习笔记(五)----协同IResult

Caliburn.Micro学习笔记(五)----协同IResult 今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows custom code to execute after the return of a action. /// </summary> public interface IResult { /// <summary> /// Executes the result using the specif

angular学习笔记(五)-阶乘计算实例(1)

<!DOCTYPE html> <html ng-app> <head> <title>2.3.2计算阶乘实例1</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="script.js"></script> </

NLTK学习笔记(五):分类和标注词汇

[TOC] 词性标注器 之后的很多工作都需要标注完的词汇.nltk自带英文标注器pos_tag import nltk text = nltk.word_tokenize("And now for something compleyely difference") print(text) print(nltk.pos_tag(text)) 标注语料库 表示已经标注的标识符:nltk.tag.str2tuple('word/类型') text = "The/AT grand/J

Linux System Programming 学习笔记(五) 进程管理

1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件) A process is a running program A thread is the unit of activity inside of a process the virtualization of memory is associated with the process, the threads all share the same memory address space 2. pid The idle pro

java之jvm学习笔记五(实践写自己的类装载器)

java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类装载器和安全管理器是可以被动态扩展的,或者说,他们是可以由用户自己定制的,今天我们就是动手试试,怎么做这部分的实践,当然,在阅读本篇之前,至少要阅读过笔记三. 下面我们先来动态扩展一个类装载器,当然这只是一个比较小的demo,旨在让大家有个比较形象的概念. 第一步,首先定义自己的类装载器,从Clas

Java学习笔记_26_泛型概述

                                                               泛型概述 在Java中存入容器中的对象再取出时需要转换类型,因为对象加入容器会被转换成Object类型,而取出时要转换成实际类型.但向  下类型转换都 是存在潜在危险的,因此应该尽量避免它们.  Java的泛型: 所谓泛型就是在定义(类.方法.形参.成员变量等等)的时候,指 定它们为通用类型,也就是数据类型可以是任意类型. 泛型为提高大型程序的类型安全和维护带来了很大的潜

WEB前端学习笔记 五

接web前端学习笔记第四篇,此篇为web学习笔记 五,在此感谢您的采集和转发,但请注明文章出自网知博学. 2.0.3  html标签的属性格式 现在我们知道了两个双标签分别是,标题标签:<h1> - <h6>.和段落标签:<p></p>还知道了一个换行的单标签:<br />,现在我们给<p></p>标签添加一个属性,来改变段落是右对齐,还是左对齐,还是居中. 如上图,<p>标签中的 align(中文就是排列的意

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

python之list(学习笔记五)

python之list(学习笔记五) Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出公司里同事的名字,就可以用一个list表示: >>> worker = ['wtf','laotan','xiaoxian'] >>> worker ['wtf', 'laotan', 'xiaoxian'] 变量 worker 就是一个list.用 len() 函数可以获得list元素的个数: >>>

Boost Thread学习笔记五

多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage.boost::thread库为我们提供了一个接口简单的TLS的面向对象的封装,以下是tss类的接口定义: class tss{public:    tss(boost::function1<void, void*>* pcleanup);    void* get() const;    void set(void*