泛型:把类型做到通用—>代表着动态
- 什么是泛型{通用的模板}
- 如何声明和使用泛型
- 泛型的好处与原理
- 泛型类、泛型方法、泛型接口、泛型委托
- 泛型约束
- 协变 逆变
- 泛型缓存
总结:
【1】泛型的用处–让我们泛型类、泛型方法、泛型接口、泛型委托这些更–通用
【2】次要:约束用的不是很多。太通用,安全性不是很高,所以需要进行约束
【3】了解性的内容:协变逆变
以下是关于泛型的例子,里面有详细的介绍
关于泛型总结如上↑,整体细节如下↓
using System;
using System.Collections.Generic;
namespace _13泛型
{
public class Program
{
static void Main(string[] args)
{
//1.什么是泛型?
List<string> vs = new List<string>() { "编程", "测试", "AI" };
foreach (var item in vs)
{
Console.WriteLine(item);
}
//object类型做数据转换的时候有拆箱装箱的操作,有性能损耗,建议少用
List<object> objList = new List<object>() { };
List<List<string>> vs1 = new List<List<string>>();
Console.WriteLine("-----------泛型private KeyValuePair<TKey, TValue> current----------");
//泛型private KeyValuePair<TKey, TValue> current; 键/值对(泛型字典)
//TKey不能重复
Dictionary<int, string> keyValuePairs = new Dictionary<int, string>();
keyValuePairs.Add(1, "C#基础语法");
keyValuePairs.Add(2, "C#中级语法");
keyValuePairs.Add(3, "java高级语法");
foreach (var item in keyValuePairs)
{
Console.WriteLine(item.Key.ToString() + "--" + item.Value);
}
bool isContains = keyValuePairs.ContainsValue("java高级语法");
keyValuePairs.Remove(2);
Console.WriteLine(isContains);
foreach (var item in keyValuePairs)
{
Console.WriteLine(item.Key.ToString() + "--" + item.Value);
}
Console.WriteLine("---------------------自定义泛型--------------------");
//自定义泛型(泛型最大的优点就是做到了通用)
MyGeneric<string> myGeneric = new MyGeneric<string>("这是一个自定义参数");
myGeneric.Show();
MyGeneric<int> myGenericInt = new MyGeneric<int>(1000);
myGenericInt.Show();
Console.WriteLine("---------------------泛型方法--------------------");
Show(11111111);
Show1("泛型方法");
Console.WriteLine("---------------------泛型约束{条件约束}--------------------");
//【1】new() 约束--表示T类型只接收带一个无参数的构造函数
//【2】struct值类型约束
//【3】class引用类型约束
//【4】自定义类型约束(基类型约束,接口类型约束)
//值类型--结构类型stuct--int,double,bool,枚举
//引用类型--数组,类,接口,委托,object,字符串
//new() 约束,一定要写在最后面
//
Student student = new Student();
//IStudent student1 = new IStudent();//不可以进行常见对象
IStudent student1 = null;
Show(student);
ShowStudent(student);
Student2 student2 = new Student2();
//ShowStudent(student2);//纯属别的对象,不会被方法接受 要传输规定的类型
Console.WriteLine("---------------------协变和逆变--------------------");
People people = new People();
People people1 = new People();
Teacher teacher = new Teacher();
//Teacher teacher1 = new People();
List<People> listOut = new List<People>();
//【1】其实从现实中理解,他应该正确才对,但是List<People>类型和List<Teacher>()不是一个类型,从类型的角度来不成立
//,所以,其实这个是语法规则不支持。.net2.0,3.0的时候才有协变和逆变
//【2】协变和逆变他是针对接口和泛型委托来说的。离开了他们就没有这个说法。
//【3】out关键字代表协变,in代表逆变
//【4】什么情况下使用???在知道自己或别人以后有用到弗雷通过子类实例化,或者子类通过弗雷实例化的
//的情况下可以out或者in关键字
//List<People> listOut = new List<Teacher>();
IListOut<People> listOut1 = new ListOut<People>();
IListOut<People> listOut2 = new ListOut<Teacher>();//协变
IListIN<Teacher> listIN = new ListIN<Teacher>();
IListIN<Teacher> listIN1 = new ListIN<People>();//逆变
IOutInList<Teacher, People> myList1 = new OutIntList<Teacher, People>();
IOutInList<Teacher, People> myList2 = new OutIntList<Teacher, Teacher>();//协变
IOutInList<Teacher, People> myList3 = new OutIntList<People, People>();//逆变
IOutInList<Teacher, People> myList = new OutIntList<People, Teacher>();//逆变+协变
Console.ReadKey();
}
#region 泛型方法
public static void Show<T, S, K, D>(T t)
where D : Student, IStudent, IStudent<T>//基类约束,只能有一个而且要放前面,接口约束可以多个 {where D : Student,Student2, IStudent, IStudent<T>}
where S : struct
where T : class, new()
{
Console.WriteLine(t);
}
// public static void ShowMany<T>(T t)
//where T : struct, Student//又是值类型又是引用类型是不合理的
// {
// Console.WriteLine(t);
// }
// public static void ShowMany<T>(T t)
//where T : struct, new()
// {
// int i = new int();//是可以创建空间的,不可以重复使用
// Console.WriteLine(t);
// }
// public static void ShowMany<T>(T t)
//where T : class, new()//符合常理,同时使用多个条件
// {
// int i = new int();
// Console.WriteLine(t);
// }
//可以多条件约束
public static void ShowMany<D, S, T>(D d, S s, T t)
where D : IStudent
where S : struct
where T : class, new()
{
int i = new int();
Console.WriteLine(t);
}
public static void ShowStudent<T>(T t)
where T : Student//固定了对象
{
Console.WriteLine(t);
}
public static void Show<T>(T t) where T : new()//约束--表示T类型只接收一个无参的构造函数new T()实例化一个对象
{
Console.WriteLine(t);
}
/// <summary>
/// 泛型方法,可以多个Show<T,K>(T t,K k)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public static void Show1<T>(T t)
{
Console.WriteLine(t.ToString());
}
#endregion
}
public class People
{
public int Id { get; set; }
}
public class Teacher : People//子类
{
public string Name { get; set; }
}
#region 协变
/// <summary>
/// 协变只能返回结果,不能做参数
/// </summary>
/// <typeparam name="T"></typeparam>
interface IListOut<out T>
{
T GetT();
}
class ListOut<T> : IListOut<T>
{
public T GetT()
{
return default(T);//default关键字,如果是值类型默认返回0,是引用类型默认返回null
}
}
#endregion
#region 逆变
/// <summary>
/// in修饰,逆变后,T只能作为当参数 不能做返回值
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IListIN<in T>
{
//T GetT();//不能使用
void Show(T t);//与协变相反
}
class ListIN<T> : IListIN<T>
{
public void Show(T t)
{
//throw new NotImplementedException();
}
}
#endregion
#region 协变+逆变
public interface IOutInList<in inT, out outT>
{
void Show(inT t);
outT Get();
outT Do(inT t);
//out 只能是返回值, in只能是参数
//void Show1(ouT t);
//inT Get1();
}
public class OutIntList<T1, T2> : IOutInList<T1, T2>
{
public T2 Do(T1 t)
{
return default(T2);
//throw new NotImplementedException();
}
public T2 Get()//协变作为返回值
{
throw new NotImplementedException();
}
public void Show(T1 t)//逆变作为参数
{
throw new NotImplementedException();
}
}
#endregion
#region 泛型约束
public interface IStudent<T>//泛型接口
{
}
public interface IStudent//普通接口
{
//没有构造函数
}
public class Student//普通类
{
//默认有一个无参数的构造
}
public class Student2//普通类
{
//默认有一个无参数的构造
}
public class Student3<T> : Student//继承Student
{
//默认有一个无参数的构造
}
public class Student4<T> : Student where T : new()//继承Student where T :new()是约束
{
//默认有一个无参数的构造
}
/// <summary>
/// 泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
class MyGeneric<T>
{
private T t;
public MyGeneric(T t1)
{
this.t = t1;
}
public void Show()
{
Console.WriteLine(t);
}
}
#endregion
}