C#自学笔记:泛型编程
泛型
概念
泛型实现了类型参数化,达到代码重用目的通过类型参数化来实现同一份代码上操作多种类型
• 泛型相当于类型占位符
• 定义类或方法时使用替代符代表变量类型
• 当真正使用类或者方法时再具体指定类型
泛型分类
- 泛型类和泛型接口
基本语法:
class 类名<泛型占位字母>
interface 接口名<泛型占位字母>
- 泛型函数
基本语法:
函数名<泛型占位字母>(参数列表)
注意:泛型占位字母可以有多个,用逗号分开
泛型类和接口
使用//类
class TestClass<T>
{
public T value;
}
class TestClass2<T1, T2, K, M, LL, Key, Value>
{
public T1 value1;
public T2 value2;
public K value3;
public M value4;
public LL value5;
public Key value6;
public Value value7;
}
//使用
TestClass<int> t = new TestClass<int>();
t.value = 10;
TestClass<string> t2 = new TestClass<string>();
t2.value = "123123";
TestClass2<int, string, float, double, TestClass<int>, uint, short> t3 = new TestClass2<int, string, float, double, TestClass<int>, uint, short>();
//接口
interface TestInterface<T>
{
T value
{
get;
set;
}
}
class Test :TestInterface<int>
{
public int value {get => throw new NotImplementedException();
set => throw new NotImplementedException(); }
}
泛型方法
使用//普通类中的泛型方法
class Test2
{
public void TestFun<T>(T value)
{
Console.WriteLine(value);
}
public void TestFun<T>()
{
T t = defalut(T);
}
public T TestFun<T>(string v)
{
return default(T);
}
public void TestFun<T, K, M>(T t, K k, M m)
{
}
}
//使用
Test2 tt = new Test2();
tt.TestFun<string>("123123");
//泛型类中的泛型方法
class Text2<T>
{
public T value;
//这个不叫泛型方法,因为T是泛型类声明的时候就指定了
public void TestFun(T t)
{
}
//这个才是泛型方法
public void TestFun<K>(K k)
{
Console.WriteLine(k);
}
}
作用
- 不同类型对象的相同逻辑处理就可以选择泛型
- 使用泛型可以一定程度避免装箱拆箱
举例:优化ArrayList,使用泛型确定对象类型,避免装箱拆箱
泛型约束
让泛型的类型有一定的限制,意思就是这个泛型只能是约束的类型关键字:where
泛型约束一共有6种
| 类型 | 语法 |
|---|---|
| 值类型 | where 泛型字母:struct |
| 引用类型 | where 泛型字母:class |
| 存在无参公共构造函数,并且是非抽象类型 | where 泛型字母:new() |
| 某个类本身或者其派生类 | where 泛型字母:类名 |
| 某个接口的派生类型 | where 泛型字母:接口名 |
| 另一个泛型类型本身或者派生类型 | where 泛型字母:另一个泛型字母 |
举例:
class Test1<T> where T : struct
{
}
代表T类型一定是结构体或其他的值类型
class Test2<T, U> where T : U
{
}
interface IFly
{
}
class Test3 : IFly
{
}
//使用
Test2<Test3, IFly> t6 = new Test2<Test3, IFly>();
代表T一定是继承或实现接口U的
约束的组合使用
组合有些不能一起使用,只需要写上去如果报错就说明不能一起组合注意:一般情况下new()放在最后,否则容易报错
class Test<T> where T : class, new()
{
}
同时多个泛型有约束
直接接在后面即可class Test<T, K> where T : class, new() where K : struct
{
}
List
本质List是一个c#为我们封装好的类,它的本质是一个可变类型的泛型数组,List类帮组我们实现了很多方法,比如泛型数组的增删改查。
使用
List<int> list = new List<int>();
List<string> list2 = new List<string>();
//增
list.Add(1);
list2.Add("123");
List<string> listStr = new List<string>();
listStr.Add("123");
list2.AddRange(listStr);
list.Insert(0, 999);
//删
list.Remove(1);
list.RemoveAt(0);
list.Clear();
//查
Console.WriteLine(list[0]);
if (list.Contains(1)
{
Console.WriteLine("存在元素");
}
//正向查找,找不到时返回-1
int index = list.IndexOf(5);
//反向查找
index = list.LastIndexOf(2);
//改
list[0] = 99;
遍历
//长度
Console.WriteLine(list.Count);
//容量
Console.WriteLine(list.Capacity);
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
foreach (int item in list)
{
Console.WriteLine(item);
}
Dictionary
本质可以将Dictionary理解为拥有泛型的Hashtable
它也是基于键的哈希代码组织起来的键/值对
键值对类型从Hashtable的object变为了可以自己制定的泛型
使用
using System.Collections.Generic
Dictionary<int, string> dictionary = new Dictionary<int, string>();
//增
dictionary.Add(1, "123");
//删
dictionary.Remove(1);
dictionary.Clear();
//查
//1. 通过键查看值
//找不到直接报错
Console.WriteLine(dictionary[2]);
//2. 查看是否存在
//根据键检测
if (dictionary.ContainsKey(4))
{
Console.WriteLine("存在");
}
//根据值检测
if (dictionary.ContainsValue("1234")
{
Console.WriteLine("存在");
}
//改
dictionary[1] = "555";
遍历
//长度
Console.WriteLine(dictionary.Count);
//1. 遍历所有键
foreach(int item in dictionary.Keys)
{
Console.WriteLine(item);
Console.WriteLine(dictionary[item]);
}
//2. 遍历所有值
foreach(string item in dictionary.Values)
{
Console.WriteLine(item);
}
//3. 键值对一起遍历,KeyValuePair不好记
foreach(KeyValuePair<int, string> item in dictionary)
{
Console.WriteLine("键:" + item.Key + "值:" + item.Value);
}
自己实现一个最简单的单向链表
//单向链表节点
class LinkedNode<T>
{
public T value;
public LinkedNode<T> nextNode;
public LinkedNode(T value)
{
this.value = value;
}
//单向链表类
class LinkedList<T>
{
//只是一个引用,没有实例化,指向的实例可以通过add不断改变
public LinkedNode<T> head;
public LinkedNode<T> last;
public void Add(T value)
{
LinkedNode<T> node = new LinkedNode<T>(value);
if (head == null)
{
head = node;
last = node;
}
else
{
last.nextNode = node;
last = node;
}
}
public void Remove(T value)
{
if (head == null)
{
return;
}
if (head.value.Equals(value))
{
head = head.nextNode;
if (head == null)
{
last = null;
}
return;
}
LinkedNode<T> node = head;
while (node.nextNode != null)
{
if (node.NextNode.value.Equals(value))
{
if (node.NextNode == last)
{
last = node;
node.nextNode = null;
}
else
{
node.nextNode = node.nextNode.nextNode;
}
break;
}
node = node.nextNode;
}
}
}
LinkedList
本质LinkedList是一个c#为我们封装好的类,它的本质是一个可变类型的泛型双向链表
使用
using System.Collections.Generic
LinkedList<int> linkedList = new LinkedList<int>();
//增
//1. 在链表尾部添加元素
linkedList.AddLast(10);
//2. 在链表头部添加元素
linkedList.AddFirst(20);
//3. 在某一个节点之后添加一个节点
LinkedListNode<int> n = linkedList.Find(20);
linkedList.AddAfter(n, 15);
//4. 在某一个节点之前添加一个节点
linkedList.AddBefore(n, 11);
//删
//1. 移除头节点
linkedList.RemoveFirst();
//2. 移除尾节点
linkedList.RemoveLast();
//3. 移除指定节点
linkedList.Remove(20);
//4. 清空
linkedList.Clear();
//查
//1. 头节点
LinkedListNode<int> first = linkedList.First;
//2. 尾节点
LinkedListNode<int> last = linkedList.Last;
//3. 查找指定值的节点
//只能遍历查找
//找不到时会返回空
LinkedListNode<int> node = linkedList.Find(3);
//4. 判断是否存在
if (linkedList.Contains(1))
{
Console.WriteLine("链表中存在");
}
//改
//要先得到节点,再改变其中的值
linkedList.First.Value = 10;
遍历
//1. foreach遍历
foreach(int item in linkedList)
{
Console.WriteLine(item);
}
//2. 通过节点遍历
//从头到尾
LinkedListNode<int> nowNode = linkedList.First;
while (nowNode != null)
{
Console.WriteLine(nowNode.value);
nowNode = nowNodw.Next;
}
//从尾到头
nowNode = linkedList.Last;
while(nowNode != null)
{
Consolw.WriteLine(nowNode.Value);
nowNode = nowNode.Previous;
}
泛型Stack
使用上和之前的Stack一模一样Stack<int> stack = new Stack<int>();
泛型Queue
使用上和之前的Queue一模一样Queue<object> queue = new Queue<object>();

浙公网安备 33010602011771号