using System.Collections;
namespace Leason1_ArrayList
{
class Test { }
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("ArrayList");
#region ArrayList性质
//ArrayList是一个c#为我们封装好的类
//它的本质是一个object类型的数组
//ArrayList 类帮助我们实现了许多方法
//比如数组的增删改查
#endregion
#region 申明
//需要引用System.Collections命名空间
ArrayList arryList = new ArrayList();
#endregion
#region 增删改查
//增
arryList.Add(1);//单独增加
arryList.Add("sd");
arryList.Add(true);
arryList.Add(new Test());
arryList.Add(1);
ArrayList arryList2 = new ArrayList();
arryList2.Add("sd1");
arryList.AddRange(arryList2); //拼接增加 把另外一个list的内容加到后面
//插入增加
arryList.Insert(1, "12345");
//指定插入到那个位置 就会放到哪个位置
//删
arryList.Remove(1);//移除指定的元素 从头开始找 找到就删 当出现重复的时候 只会删除前面的哪一个
arryList.RemoveAt(2);//删除指定位置的元素
//arryList.Clear(); //清空
//改
arryList[1] = "zzw";
//查
Console.WriteLine(arryList[0]);//得到指定位置的元素
if (arryList.Contains("sd") ){ //查看元素是否存在
Console.WriteLine("存在");
}
//正向查找元素位置 找到返回位置 没找到返回-1 当出现重复的时候 只会返回前面哪一个
int index = arryList.IndexOf(true);
Console.WriteLine("true位置是{0}", index);
//反向查找元素位置 返回从头开始的索引数
int index1 = arryList.LastIndexOf(true);
Console.WriteLine("true位置是{0}", index1);
#endregion
#region 遍历
//长度
Console.WriteLine(arryList.Count);
//容量
//避免产生过多的垃圾
Console.WriteLine(arryList.Capacity);
for(int i =0;i<arryList.Count;i++)
{
Console.WriteLine(arryList[i]);
}
//迭代器遍历
foreach(object item in arryList) {//要用object 不能用ArryList
Console.WriteLine(item);
}
#endregion
# region 装箱拆箱
//ArryList本质上是一个可以自动扩容的object数组
//由于用万物之父进行存储数据 自然存在装箱拆箱
//当往其中进行值类型存储时就是在装箱 当将值类型取出来转换的使用时 就是在拆箱
//ArryList最好少用
int i = 1;
arryList[1] = 1;//装箱
i = (int)arryList[1];//拆箱
#endregion
}
}
}
using System.Collections;
namespace Leason2_Stack
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Stack");
#region Stack本质
//Stack(栈)是一个c#为我们封装好的类
//它的本质也是object【】数组 只是封装了特殊的存储规则
//Stack 时栈存储容器 栈是一种先进后出的数据结构
//先存入的数据后获取 后存入的数据先获取
#endregion
#region 申明
//需要引用System.Collections命名空间
Stack stack = new Stack();
#endregion
#region 增取查改
//增 压栈 只能一个一个的放 一个一个的取
stack.Push(1);
stack.Push("weqe");
stack.Push(true);
stack.Push(1);
//取
//栈中不存在删除的概念
//只有取的概念
//弹栈
object v=stack.Pop();
Console.WriteLine(v); //取出最上面的那个元素
v = stack.Pop(); //此时由于最上面的那个值被取出来了 此时取倒数第二个
Console.WriteLine(v);
//查
//栈无法查看指定位置的元素
//只能查看栈顶的元素
v=stack.Peek();
Console.WriteLine(v);
//查看是否在栈中
if (stack.Contains(true))
{
Console.WriteLine("存在");
}
else
{
Console.WriteLine("不存在");
}
//改
//栈无法改变其中的元素 只能压(存)和弹(取)
//实在要改 只能清空
//stack.Clear();
#endregion
#region 遍历
//长度
Console.WriteLine(stack.Count);
//foreach遍历 (因为没法用for循环)
//而遍历出来的顺序 也是 栈顶 到 栈底
foreach (object o in stack)
{
Console.WriteLine(o);
}
//还有一种遍历方式
//将栈转换成object数组
//遍历出来的顺序也是从栈顶到栈底
object[] arr = stack.ToArray();
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine(arr[i]);
}
//循环弹栈
while(stack.Count > 0)
{
Console.WriteLine(stack.Pop());
}
#endregion
//同样存在装箱和拆箱
}
}
}
using System.Collections;
namespace Leason3_Queue
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Queue");
#region 性质
//Queue是一个c#为我们封装好的类
//它的本质也是object[]数组 只是封装了特殊的规则
//Queue是队列存储容器
//队列是一种先进先出的数据结构
//先存入的数据先获取 后存入的数据后获取
//先进先出
#endregion
#region 申明
//需要引用System.Collections命名空间
Queue queue = new Queue();
#endregion
#region 增取改查
//增 一个一个的增加 一个一个读取
queue.Enqueue(1);
queue.Enqueue("qwweqwe");
queue.Enqueue(new int[2]);
queue.Enqueue(true);
//取
//队列不存在删除的概念
//只有取的概念 取出先加入的对象
object v= queue.Dequeue();
Console.WriteLine(v);
v = queue.Dequeue();
Console.WriteLine(v);
//改
//队列不能改变其中的元素 只能进出队列
//要改只能清
queue.Clear();
//查
// 查看头部元素但不会取出
v = queue.Peek();
Console.WriteLine(v);
//查看元素是否存在于队列中
if(queue.Contains(true)){
Console.WriteLine("存在");
}
#endregion
#region 遍历
//长度
Console.WriteLine(queue.Count);
//foreach补全
foreach(object itm in queue) {
Console.WriteLine(itm);
}
//转换成object数组
object[] objects = queue.ToArray();
for(int i = 0; i < objects.Length; i++)
{
Console.WriteLine(objects[i]);
}
//循环出列
while(queue.Count > 0)
{
object o = queue.Dequeue();
Console.WriteLine(o);
}
#endregion
//存在装箱拆箱
}
}
}
using System.Collections;
namespace Leason4_Hashtable
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hashtable");
#region Hashtable本质
//Hashtable(又称散列表) 是基于键的哈希代码组织起来的键/值对
//它的主要作用是提高数据查询的效率
//使见来访问集合中的元素
#endregion
#region 申明
//需要引用System.Collections命名空间
Hashtable hashtable = new Hashtable();
#endregion
#region 增删改查
//增 键 值
hashtable.Add(1, 123);
hashtable.Add("WEQE", 1);
hashtable.Add(true, true);
hashtable.Add(4, new int[2]);
//删
//只能通过键取删除
hashtable.Remove("WEQE");
//删除不存在的 没有反应
//或者直接清空
//hashtable.Clear();
//改
//只能改 键对应的值内容 不能修改键
Console.WriteLine(hashtable[1]);
hashtable[1] = "321";
Console.WriteLine(hashtable[1]);
//查
//通过键查看值 找不到返回空
Console.WriteLine(hashtable["WEQE"]); //null
Console.WriteLine(hashtable[2]); //null
//查看是否存在
//根据键检测
if (hashtable.Contains(1))//默认是键检测
{
Console.WriteLine("存在 ");
}
if (hashtable.ContainsKey(1))
{
Console.WriteLine("存在 ");
}
//根据值检测
if (hashtable.ContainsValue(123))
{
Console.WriteLine("存在");
}
#endregion
#region 遍历
Console.WriteLine(hashtable.Count); //得到键值对数
//遍历所有的键
foreach (object item in hashtable.Keys)
{
Console.WriteLine(item);
Console.WriteLine(hashtable[item]);
}
//遍历所有值
foreach (object item1 in hashtable.Values)
{
Console.WriteLine(item1);
}
//键值对一起遍历
foreach(DictionaryEntry item2 in hashtable)
{
Console.WriteLine("键"+item2.Key+"值"+item2.Value);
}
{
}
#endregion
}
}
}
namespace Leason5_泛型
{
#region 泛型是什么
//泛型实现了类型参数化 达到代码重用目的
//通过类型参数话来实现同一份代码上操作很多种类型
//泛型相当于类型占位符
//定义类或方法时使用替换符代表变量类型
//当真正使用类或者方法时再具体指定类型
#endregion
#region 泛型分类
//泛型类和泛型接口
//基本语法
//class 类名 <泛型占位字母>
//interface 接口名<泛型占位字母>
//泛型函数
//基本语法 :函数名<泛型占位字母>(参数列表)
//注意:泛型占位字母可以有多个 用逗号分开
class TessClass<T>
{
public T value;
}
class TessClass1<T1,T2,K,M>
{
public K value;
public T1 value1;
public T2 value2;
public M value3;
}
interface TessInterface<T>
{
T Value
{
get;
set;
}
}
class Test : TessInterface<int>
{
public int Value { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
//泛型函数
class Test1
{
public void Testfun<T,K>(T value)
{
Console.WriteLine(value);
}
public void Testfun<T, K>()
{
T t = default(T);///default()可以得到默认值
Console.WriteLine();
}
}
class Test1<T> //加了泛型就是新的类了
{
public T values;
public void Test<T1>()//这是泛型方法
{
Console.WriteLine(values);
}
public void Test(T t)//此时不能叫泛型方法了 因为T是泛型类申明的时候 就指定在这个函数中 我们不能再动态变化
{
Console.WriteLine(t);
}
}
#endregion
#region 泛型的作用
//不同类型对象的相同逻辑处理就可以选择泛型
//使用泛型可以一定程度上避免装箱拆箱
//比如优化ArryList
class ArryList<T>
{
private T[] arry;
public void Add(T t)
{
}
public void Remove(T t)
{
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("泛型");
TessClass<int> i = new TessClass<int>();
i.value = 1;
Console.WriteLine(i.value);
Test1 test1 = new Test1();
test1.Testfun<int, int>(123);
}
}
}
using System.Runtime.InteropServices;
namespace Leason6_泛型约束
{
#region 泛型约束概念
//让泛型的类型有一定的限制
//关键字 where
//泛型约束一共有6种
//1 值类型 where 泛型字母:struct
//2 引用类型 where 泛型字母:class
//3 存在无参公共构造函数 where 泛型字母 :new()
//4 某个类本身或者派生类 where 泛型字母:类名
//5 某个接口派生类型 where 泛型字母:接口名
//6 另一个泛型类型本身或者派生类型 where 泛型字母 :另一个泛型字母
#endregion
#region 各种泛型约束
//1 值类型
class Test1<T> where T : struct
{
public T values;
public void Tee<M>(M a) where M : struct
{
Console.WriteLine(a);
}
}
//2 引用类型
class Test2<T> where T : class
{
public T values;
public void Tee<M>(M a) where M : class
{
}
}
//3 存在无参 公共 构造函数的 非抽象 类型
class T1
{
}
class T2
{
public T2(int i)
{
}
}
class T3
{
private T3()
{
}
}
class Test3<T> where T : new()
{
public T values;
public void Tee<M>(M a) where M : new()
{
}
}
//4 某个类本身或者派生类
class Test4<T> where T : T1
{
public T values;
public void Tee<M>(M a) where M :T1
{
}
}
//5 某个接口派生类型
interface Fy
{
}
class T4 : Fy
{
}
class Test5<T> where T : Fy
{
public T values;
public void Tee<M>(M a) where M : Fy
{
}
}
//6 另一个泛型类型本身或者派生类型
class Test6<T,U> where T : U
{
public T values;
public void Tee<M>(M a) where M : U
{
}
}
#endregion
#region 约束的组合使用
class Test7<T> where T :class, new()//new()一般写在最后
{
public T values;
public void Tee<M>(M a) where M :class, new()
{
}
}
#endregion
#region 多个泛型约束
class Test8<T,K> where T : class, new() where K : new()
{
public T values;
public void Tee<M>(M a) where M : class, new()
{
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("泛型约束");
//3 存在无参 公共 构造函数的 非抽象 类型
Test3<T1> t1 = new Test3<T1>();//T1存在无参构造函数 可行
// Test3<T2> t1 = new Test3<T2>(); T2没有无参构造函数不可行
// Test3<T3> t1 = new Test3<T3>(); T3中无参构造函数是私有的不可行
//5 某个接口派生类型
Test5<Fy> test5 = new Test5<Fy>();
test5.values = new T4();
//6 另一个泛型类型本身或者派生类型
Test6<T4,Fy> test6=new Test6<T4,Fy>();//T4继承了Fy
}
}
}
namespace Leason7_List
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("List");
//List 是一个C#为我们封装好的类
//它的本质是一个可变类型的泛型数组
//List类帮助我们实现了很多的方法
//比如泛型数组的增删改查
#region 申明
List<int> list = new List<int>();
List<string> list1 = new List<string>();
#endregion
//增
list.Add(1); //因为List是List<int>型,只能添加int
list.Add(2);
list.Add(3);
list.Add(4);
list1.Add("sda");
List<string> list2 = new List<string>();
list2.Add("1");
list1.AddRange(list2);//把list2加在list1后面
list.Insert(0, 999);//在指定位置增加值
//删
//删除指定元素
list.Remove(1);
//移除指定位置的元素
list.RemoveAt(0);
//清空
//list.Clear();
//查
//得到指定位置的元素
Console.WriteLine(list[1]);
//查看指定元素是否存在
if (list.Contains(1))
{
Console.WriteLine("存在");
}
else
{
Console.WriteLine("不存在");
}
//正向查找 找不到返回-1
int indes = list.IndexOf(4);
//反向查找 找不到返回-1
int index = list.LastIndexOf(2);
//改
Console.WriteLine(list[1]);
list[1] = 123;
//遍历
Console.WriteLine(list.Count);//长度
Console.WriteLine(list.Capacity);//容量
}
}
}
namespace Leason8_Dictionary
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Dictionary");
#region 本质
//可以把Dictionary理解为拥有泛型的Hashtable
//它也是基于哈希代码组织起来的键/值对
//键值对类型从Hashtable的oobject变成了可以自己制定的泛型
#endregion
#region 申明
Dictionary<int,string> dictionary = new Dictionary<int,string>();
#endregion
#region 增删查改
//不能出现相同的键
//增
dictionary.Add(1, "sd");
dictionary.Add(2, "sd");
dictionary.Add(3, "sd");
dictionary.Add(4, "sd");
//删 通过键去删除
dictionary.Remove(1);
dictionary.Remove(5);
// dictionary.Clear();
//查
//找不到直接报错
Console.WriteLine(dictionary[1]);
// Console.WriteLine(dictionary[5]);//不存在的话会报错
//查看是否存在
//1 键检测
if(dictionary.ContainsKey(1))
{
}
//2 值检测
if(dictionary.ContainsValue("sd")) {
}
//改
dictionary[2] = "wse";
#region 遍历
int index = dictionary.Count;//长度
//遍历所有键
foreach (int item in dictionary.Keys)
{
Console.WriteLine(item);
Console.WriteLine(dictionary[item]);
}
//遍历所有值
foreach(string item in dictionary.Values)
{
Console.WriteLine(item);
}
//键值对一起遍历
foreach(KeyValuePair<int,string> item in dictionary)
{
Console.WriteLine("键:"+item.Key+"值"+item.Value);
}
#endregion
#endregion
}
}
}
namespace Leason9_顺序存储和链式存储
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("顺序存储和链式存储");
#region 数据结构
//数据结构
//数据结构是计算机存储,组织数据的方式(规则)
//数据结构上是指互相之间存在一种或多种特定关系的数据元素的集合
//比如自定义的一个类 也可以称之为一种数据结构 自己定义的数据组合规则
//不要把数据结构想的太复杂
//简单点说 就是人定义的存储数据 和表示数据之间关系的规则而已
//常用的数据结构(前辈总结和指定的一些经典规则)
//数组,栈,队列,链表,树,图,堆,散列表
#endregion
#region 线性表
//线性表是一种数据结构 是由n个具有相同特性的数据元素的有限序列
//比如数组,ArryList,Stack,Queue,链表等等
#endregion
//顺序存储和链式存储 是数据结构两种 存储结构
#region 顺序存储 (地址连续)
//数组,Stack,Queue,List,ArryList---顺序存储
//只是 数组 Stack Queue的 组织规则不同而已
//顺序存储
//用一组地址连续的存储单元依次存储现象表中的各个数据元素
#endregion
#region 链式存储
//单向链表,双向链表,循环链表-链式存储
//链式存储(链接存储):
//用一组任意的存储单元存储线性表中的各个数据元素
#endregion
#region 实现一个简单的单向链表
LinkNode<int> node = new LinkNode<int>(1);
LinkNode<int> node1 = new LinkNode<int>(1);
node.nextNode = node1;
node1.nextNode = new LinkNode<int>(1);
node1.nextNode.nextNode= new LinkNode<int>(1);
#endregion
}
}
/// <summary>
/// 单向链表节点
/// </summary>
/// <typeparam name="T"></typeparam>
class LinkNode<T>
{
public T value;
//存储下一个元素是谁 相当于钩子
public LinkNode<T> nextNode;
public LinkNode(T value)
{
this.value = value;
}
}
/// <summary>
/// 单向链表类 管理节点
/// </summary>
/// <typeparam name="T"></typeparam>
class LinkList<T>
{
public LinkNode<T> head;
public LinkNode<T> tail;
public void Add(T value)
{
//添加节点 必然是new一个新的节点
LinkNode<T> node = new LinkNode<T>(value);
if(head == null)
{
head = node;
tail = node;
}
else
{
tail.nextNode = node;
}
}
public void Remove(T value)
{
if(head == null)
{
return;
}
if (head.value.Equals(value) )
{
head = head.nextNode;
//如果头节点 被移除后发现头节点变空
//证明只有一个节点 那tail也要是清空
if (head == null)
{
tail = null;
}
return;
}
//此时遍历链表 产找移除的节点
LinkNode<T> node = head;
while (node.nextNode!=null) {
if (node.nextNode.value.Equals(value))
{
//让当前找到的这个元素的上一个节点 指向自己的下一个节点
node.nextNode=node.nextNode.nextNode;
break;
}
}
}
}
#region 顺序存储和链式存储的优缺点
//从增删改查的角度思考
//增:链式存储 计算上 优于顺序存储 (中间插入时链式不用像顺序一样去移动位置
//删 链式存储 计算上 优于顺序存储 (中间删除时链式不用像顺序一样去移动位置
//查:顺序存储 使用上 由于链式存储 (数组可以直接通过下标得到元素 链式需要遍历)
//改:顺序存储 使用上 优于链式存储 (数组可以通过下标得到元素 链式需要遍历)
#endregion
}
namespace Leason10_LinkedList
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("LinkedList");
//LinkedList是一个c#为我们封装好的类
//它本质上是一个可变类型的泛型双向链表
#region 申明
//引用命名空间System.Collections.Generic
LinkedList<int> list = new LinkedList<int>();
LinkedList<string> list1 = new LinkedList<string>();
#endregion
#region 增删查改
//增
//1 在链表尾部添加元素
list.AddLast(1);
//2 在链表头部添加元素
list.AddFirst(2);
//3 在某一个节点之后添加一个节点
//要指定节点 先得到一个节点
LinkedListNode<int> node = list.Find(1);
list.AddAfter(node, 3);
//4 在某一个节点之前添加一个节点
//要指定节点 先得到一个节点
LinkedListNode<int> node1 = list.Find(1);
list.AddBefore(node1, 4);
//删
//1 移除头节点
list.RemoveFirst();
//2.移除尾节点
list.RemoveLast();
//3 移除指定节点
//无法通过位置直接移除
list.Remove(1);
//4 清空
list.Clear();
//查
//1 头节点
LinkedListNode<int> first = list.First;
//2 尾节点
LinkedListNode<int> last = list.Last;
//3 找到指定值的节点
//无法直接通过下表获取中间元素
//只有遍历查找指定位置元素
LinkedListNode<int> node2 = list.Find(1);
//4 判断是否存在
if (list.Contains(1))
{
Console.WriteLine("存在");
}
#endregion
#region 遍历
//foreach
foreach (int i in list)
{
Console.WriteLine(i);
}
//通过节点遍历
//从头到尾
LinkedListNode<int> nowHead = list.First;
while(nowHead != null)
{
nowHead = nowHead.Next;
}
//从尾到头
nowHead = list.Last;
while (nowHead != null)
{
nowHead = nowHead.Previous;
}
#endregion
}
}
}
namespace Leasing2_委托//存储行为
{
#region 委托是什么
//委托是 函数(方法)的容器
//可以理解为表示函数(方法)的变量类型
//用来存储 传递函数(方法)
//委托的本质是一个类 用来定义函数(方法)的类型(返回值和参数的类型)
//不同的函数 必须对应和各自”格式“一致的委托
#endregion
#region 基本语法
//关键字:delegate
//语法:访问修饰符 delegate 返回值 委托名(参数列表);
//写在哪里
//1 可以申明在namespace和class语句块中
//2 更多写在namespace中
//简单记忆委托法就是 函数申明语法前加一个delegate关键字
#endregion
#region 定义自定义委托
//访问修饰默认不写为 public 在别的命名空间中也能使用
//private 其他命名空间就不能用了
//一般使用public
//申明了一个可以用来存储无参无返回值函数的容器
//这里只是定义了规则 并没有使用
delegate void MyFun();
//在同一语句块中 委托规则的申明是不能重名的
//申明了一个返回值是int 有一个int参数的函数的委托容器规则
delegate int MyFun1(int x);
#endregion
#region 使用定义好的委托
//委托变量是函数的容器
//委托常用在:
//1 作为类的成员
//2 作为函数的参数
class Test
{
public MyFun fun;//没有实例化 默认为空
public MyFun1 fun1;
#region 委托变量可以存储多个函数(多播委托)
public void TestFun(MyFun fun,MyFun1 fun1)
{
//先处理一些其他的逻辑 当这些逻辑处理完了 再执行传入的函数
int i = 1;
i *= 2;
i++;
this.fun = fun;
this.fun1 = fun1;
fun();
fun1(i);
}
//增
public void AddFun(MyFun fun,MyFun1 fun1)
{
this.fun += fun;
this.fun1 += fun1;
}
//删
public void RemoveFun(MyFun fun,MyFun1 fun1) {
this.fun -= fun;
this.fun1 -= fun1;
}
#endregion
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("委托");
//专门用来装载 函数的容器
MyFun f = new MyFun(Fun);
Console.WriteLine("123");
Console.WriteLine("123");
Console.WriteLine("123");
Console.WriteLine("************");
f.Invoke();
MyFun f2 = Fun;//跟上面申明本质一样 是简化写法
f2();//跟f.Invoke()本质一种 也是简化写法
MyFun1 f3 = new MyFun1(Fun3);
Console.WriteLine(f3(1));
Test test = new Test();
test.TestFun(f, f3);
//如何用委托存储多个函数
MyFun ff = Fun;
ff += f2; //此时ff里面存了两个Fun Fun会调用两次
ff();
MyFun ff2 = null;
ff2 += Fun;
ff2 += f2;
//也可以从容器中移除指定的函数
ff2 -= f2;
ff2 -= f2;//多减 不会报错 不处理
//清空容器
ff2 = null;
#region 系统定义好的委托
//使用系统自带的需要引用命名空间using System
//1 无参无返回值 Action
Action action = Fun;
action += Fun;
action();
//2 泛型委托 Func<>
Func<string> funcString = Fun2;
//可以传n个参数
Action<int> funcInt = Fun1;
#endregion
}
static void Fun()
{
Console.WriteLine("123");
}
static void Fun1(int x)
{
}
static int Fun3(int x)
{
return 1;
}
static string Fun2()
{
return "123";
}
}
}
namespace Leason13_事件
{
#region 事件是什么
//事件是基于委托的存在
//事件 是委托的安全包裹
//让委托的使用更具有安全性
//事件 是一种特殊的变量类型
#endregion
#region 事件的使用
//申明语法
//访问修饰符 event 委托类型 事件名
//事件的使用
//1 事件是作为 成员变量存在于类当中的
//2 委托怎么用 事件就怎么用
//事件相对于委托的区别
//1 不能在类外部 赋值
//2 不能在类外部 调用
//注意
//它只能作为成员函数存在于 类 和 接口 以及 结构体 当中
//为什么有事件
//1 防止外部随意置空委托
//2 防止外部随意调用委托
//3 事件相当于堆委托进行了一次封装 让其更安全
//※ 主要区别
//1 事件不能在外部使用赋值=符号 只能使用+ - 委托 哪里都能使用
//2 事件不能在外部执行 委托哪里都能执行
//3 事件 不能作为 函数中的临时变量的 委托可以
class Test
{
//委托成员变量 用于存储 函数的
public Action myFun;
//事件成员变量 用于存储函数的
public event Action myEvent;
public Test()
{
//事件的使用和委托 一模一样 只有一些细微的区别
//1 不能在类外部 赋值
//2 不能在类外部 调用
myFun = Testfun;
myFun += Testfun;
myFun -= Testfun;
myFun();
myFun.Invoke();
myFun = null;
myEvent = Testfun;
myEvent += Testfun;
myEvent -= Testfun;
myEvent();
myEvent.Invoke();
myEvent = null;
}
public void Testfun()
{
Console.WriteLine("123");
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Test test = new Test();
//委托可以在外部赋值
test.myFun = null;
test.myFun = TestFun;
//事件不能在外部赋值
//test.myEvent=null
//test.myEvent=TestFun 这些会报错
//虽然不能直接赋值 但可以 加减 去添加移除记录的函数
test.myEvent += TestFun;
test.myEvent -= TestFun;
//委托可以在外部调用
test.myFun();
test.myFun.Invoke();
//事件不能在外部进行调用
//只能在类的内部进行封装 调用
}
static void TestFun() { }
}
}
namespace Leason14_匿名函数
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("匿名函数");
#region 什么是匿名函数
//顾名思义 就是没有名字的函数
//匿名函数的使用主要是配合委托和事件进行使用
//脱离委托和事件 就不会使用匿名函数
#endregion
#region 基本语法
//delegate(参数列表)
//{
//函数逻辑
// };
//何时使用
//1 函数中传递委托参数时
//2 委托或事件赋值时
#endregion
#region 使用
//1 无参无返回值
//这样申明匿名函数只是在申明函数而已 还没有调用
//真正调用它的时候 是这个容器啥时候调用 就啥时候调用这个匿名函数
Action a=delegate ()
{
Console.Write("匿名函数");
};
a();//使用委托 进行调用
//2 有参
Action<int,string> a1 = delegate (int an, string an1)
{
Console.WriteLine(an+an1);
};
a1(1, "sd");
//3 有返回值
Func<string> f=delegate ()
{
return "123";
};
//4 一般情况会作为函数参数传递 或者 作为 函数返回值
//参数传递
Test test = new Test();
test.DoSomething(1, delegate ()
{
Console.WriteLine("随参数申明的匿名函数逻辑");
}
);
//返回值
test.Getfun()();//直接调用
Action a22=test.Getfun();
a22();//简介调用
#endregion
#region 匿名函数的缺点
// 添加到委托或事件容器中之后 不记录 无法单独移除
#endregion
}
}
class Test
{
public Action action;
public void DoSomething(int a,Action fun)
{
Console.WriteLine(a);
fun();
}
public Action Getfun()
{
return delegate () {
Console.WriteLine("返回值匿名函数");
};
}
}
}
namespace Leason15_lambad表达式
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("lambad表达式");
#region 什么是lambad 表达式
//可以将lambad表达式 理解为匿名函数的简写
//它除了写法不同之外
//使用上和匿名函数一模一样
//都是和委托或者事件配合使用
#endregion
#region 基本语法
//(参数列表) =>
// {
//函数体
// };
#endregion
#region 使用
//1 无参无返回值
Action a = ()=>
{
Console.WriteLine("无参无返回值的lambad表达式");
};
a();
//2 有参
Action<int> a1=(int a) => {
Console.WriteLine("有参数的lambad表达式");
};
a1(123);
//3 甚至参数类型都可以省略 参数类型和委托或事件容器一致
Action<float> a2 = (float a) => {
Console.WriteLine("省略的lambad表达式");
};
a2(1.2f);
//有返回值
Func<string, int> a3 = (value) => {//()中的类型和第一个参数一致
Console.WriteLine("有返回值的lambad表达式 ");
return 1;//返回值跟第二个参数一致
};
a3("123");
//其它传参使用等和匿名函数一样
//缺点也和匿名函数一样
#endregion
}
}
#region 闭包
//内层的函数可以引用包含在它外层的函数变量
//即使外层函数的执行已经终止
//注意:
//该变量提供的值并非变量创建时的值 而是在父函数范围内的最终值
class Test
{
public event Action action;
public Test() {
int value = 1;
//这里就形成了闭包
//因为 当构造函数执行完毕时 其中申明的临时变量value的生命周期改变了
action = () =>
{
Console.WriteLine(1);
};
for(int i = 0; i < 10; i++)
{
//虽然i在变化 但存入action中的是i的最终值
action += () =>
{
Console.WriteLine(i); //此时打印10个10
};
}
for (int i = 0; i < 10; i++)
{
int index = i; //每次循环生成新的index
action += () =>
{
Console.WriteLine(index); //此时打印123456789
};
}
}
public void doaction()
{
action();
}
}
#endregion
}
namespace Leason16_List排序
{
class Item : IComparable<Item>
{
public int money;
public Item(int money)
{
this.money = money;
}
public int CompareTo(Item other)
{
//返回值的含义
//小于0:
//放在传入对象的前面
//等于0:
//保持当前位置不变
//大于0:
//放在传入对象的后面
//可以简单理解 传入对象的位置 就是0
//如果你的返回为负数 就放在它的左边 也就是前面
//如果你返回正数 就放在它的右边 也就是后面
if (this.money > other.money) //此为升序排序 若要改成降序 只需调换即可
{
return 1;
}
else
{
return -1;
}
return 0;
}
}
class ShopItem
{
public int id;
public ShopItem(int id)
{
this.id = id;
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("List排序");
#region List自带的排序方法
//系统自带的变量(int ,float,double)等一般可以直接Sort();
List<int> list = new List<int>();
list.Add(1);
list.Add(3);
list.Add(2);
list.Add(6);
list.Add(4);
list.Add(5);
//list提供的排序方法
list.Sort();
for(int i=0; i<list.Count; i++)
{
Console.WriteLine(list[i]);
}//此时123456
//ArryList 中也有Sort排序方法
#endregion
#region 自定义类的排序
List<Item> itemList = new List<Item>();
itemList.Add(new Item(2));
itemList.Add(new Item(1));
itemList.Add(new Item(4));
itemList.Add(new Item(3));
itemList.Sort();
for(int i =0; i<itemList.Count; i++)
{
Console.WriteLine(itemList[i].money);
}
#endregion
#region 通过委托函数进行排序
List<ShopItem> shopItes = new List<ShopItem>();
shopItes.Add(new ShopItem(3));
shopItes.Add(new ShopItem(15));
shopItes.Add(new ShopItem(4));
shopItes.Add(new ShopItem(6));
shopItes.Add(new ShopItem(1));
shopItes.Add(new ShopItem(8));
shopItes.Sort(SortShopItem);
//也可以用匿名函数
shopItes.Sort(delegate(ShopItem a,ShopItem b)
{
if (a.id > b.id) //升序
{
return 1;
}
else
{
return -1;
}
});
for (int i =0;i<shopItes.Count;i++)
{
Console.WriteLine(shopItes[i].id);
}
#endregion
}
static int SortShopItem(ShopItem a,ShopItem b)
{
//传入两个对象 为列表中的两个对象
//进行两两比较 用左边的和右边的条件比较
//返回值规则 和之前一样 0做标准 负数在左(前) 正数在 后
if (a.id > b.id) //升序
{
return 1;
}
else
{
return -1;
}
}
}
}
namespace Leason17_协变逆变
{
#region 什么是协变逆变
//协变:
//和谐的变化 自然的变化
//因为里氏替换原则 父类可以装子类
//所以 子类变父类
//比如 string变成object
//感受是和谐的
//逆变
//逆常规的变化 不正常的变化
//因为里氏替换原则 父类可以装子类但是子类不能装父类
//所以 父类变子类
//比如object 变成了 string
//感受是不和谐的
//协变和逆变 是用来修饰泛型的
//协变 out
//逆变 in
//只有在泛型中 修饰 泛型字母的
//只有泛型接口和泛型委托能使用
#endregion
#region 作用
//1 返回值 和参数
//用out修饰的泛型 只能作为返回值
delegate T Tesrout<out T>();
//用in修饰的泛型 只能作为参数
delegate void TestIn<in T>(T t);
//结合里氏替换原则
class Father { }
class Son:Father { }
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("协变逆变");
//协变 父类总能被子类替换
//看起来 就是son--->father
Tesrout<Son> os = () =>
{
return new Son();
};
Tesrout<Father> of = os;
Father f = of();//实际上 返回的是os里面装的函数
//逆变 父类总能被子类替换
TestIn<Father> if = (value) =>
{
};
TestIn<Son> is =if;
}
}
}