C#进阶

97 阅读16分钟

一、ArrayList

using System.Collections;


namespace Lesson1_ArrayList
{
    #region 背包类练习
    class Backpack
    {
        float money;
        ArrayList backpack;
        public Backpack(float money)
        {
            this.money = money;
            backpack = new ArrayList();
        }
        public string StoreItems(Item item)
        {
            backpack.Add(item);
            return $"物品" + item.name + "已存入背包";
        }
        public string BuyItem(Item item)
        {
            backpack.Add(item);
            this.money -= item.price;
            return $"物品" + item.name + "已购买并存入背包";
        }
        public string SellItem(string name)
        {
            foreach(Item item in backpack)
            {
                if(item.name == name)
                {
                    backpack.Remove(item);
                    this.money += item.price;
                    return $"物品" + item.name + "已卖出";
                }
            }
            return "未找到该物品";
        }
        public string ShowItemFun(string name)
        {
            foreach (Item item in backpack)
            {
                if (item.name == name)
                {
                    return $"物品" + item.name + "功能是:" + item.function;
                }
            }
            return "未找到该物品";
        }
        public float ShowMoney()
        {
            return this.money;
        }
    }
    class Item
    {
        public string name;
        public float price;
        public string function;

        public Item(string name, float price, string function)
        {
            this.name = name;
            this.price = price;
            this.function = function;
        }
    }
    #endregion
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 定义
            ArrayList array = new ArrayList();
            ArrayList array1 = new ArrayList();
            #endregion
            #region
            array.Add(123);//增加一个元素
            Console.WriteLine(array[0]);//>>123
            array1.Add(1);
            array.AddRange(array1);//增加一组
            array.Insert(1, 4565);//插入指定元素到指定位置
            #endregion
            #region
            array.Remove(123);//寻找相关元素并删除
            Console.WriteLine(array[0]);//>>1
            array.RemoveAt(0);//删除指定索引处
            array.Clear();//清空元素
            #endregion
            #region
            array.Add(1);
            array.Add(2);
            Console.WriteLine(array[0]);//查看指定索引处元素>>1
            bool b = array.Contains(2);//查看是否具有该元素,返回bool
            Console.WriteLine(b);//>>True
            Console.WriteLine(array.IndexOf(1));//查找指定元素的索引位置,找不到返回-1>>0
            Console.WriteLine(array.LastIndexOf(2));//查找指定元素,并返回从后往前遇到的第一个元素,但返回值为从前往后索引数。
            #endregion
            #region
            array[0] = 00;
            Console.WriteLine(array[0]);//>>0
            #endregion
            #region 遍历
            Console.Write(array.Count);//得到集合的Count,当前元素数量
            Console.WriteLine(array.Capacity);//得到容量
            for(int i = 0; i < array.Count; i++)
            {
                Console.WriteLine(array[i]);
            }
            //迭代器
            foreach (object item in array)
            {
                Console.WriteLine(item);
            }
            #endregion
            #region 装箱拆箱
            //ArrayList因为是一个Object类的数组,所以存在由栈上的值类型转换为堆上的引用类型的转换,所以存在装箱拆箱。
            #endregion
            #region 练习
            //请简述ArrayList和数组的区别
            //ArrayList可以存储不同的类型,可以不指定长度,某些方法不同,数组长度是Length,ArrayList是Count。

            //背包测试
            Backpack backpack = new Backpack(0);
            Item phone = new Item("手机", 3500, "打电话");
            backpack.StoreItems(phone);
            Console.WriteLine(backpack.ShowItemFun("手机"));
            Item gun = new Item("枪", 5000, "开火");
            backpack.BuyItem(gun);
            Console.WriteLine(backpack.ShowItemFun("枪"));
            backpack.SellItem("枪");
            Console.WriteLine(backpack.ShowItemFun("枪"));
            backpack.SellItem("手机");
            float money = backpack.ShowMoney(); 
            Console.WriteLine(money);
            #endregion
        }
    }
}

二、Stack

using System.Collections;
using System.Security.Cryptography.X509Certificates;//需要引入命名空间

namespace Leeson2_Stack
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 声明
            //先进后出
            Stack stack = new Stack();
            #endregion
            #region
            //压栈
            stack.Push(1);
            #endregion
            #region
            //栈中不存在删除,只有取,也叫弹栈。
            object o = stack.Pop();//一次取一个
            Console.WriteLine(o);
            #endregion
            #region 查看
            //只能查看栈顶位置的元素
            stack.Push(2);
            o = stack.Peek();
            Console.WriteLine(o);
            //检查是否存在元素
            Console.WriteLine(stack.Contains(2));
            #endregion
            #region
            //更改底部元素需要清空。
            stack.Clear();
            stack.Push(1);
            stack.Push(2);
            stack.Push(3);
            #endregion
            #region 遍历
            //长度
            Console.WriteLine("开始遍历");
            Console.WriteLine(stack.Count);
            //第一种遍历方法:
            foreach (object item in stack)
            {
                Console.WriteLine(item);
            }
            //第二种遍历方法:
            Console.WriteLine("第二种遍历开始");
            Object[] objects = stack.ToArray();
            for (int i = 0; i < objects.Length; i++)
            {
                Console.WriteLine(objects[i]);
            }
            Console.WriteLine("第三种遍历");
            //第三种遍历方法:
            while (stack.Count > 0)
            {
                object o1 = stack.Pop();
                Console.WriteLine(o1);
            }
            #endregion
            #region 练习
            //1、栈的存储规则是先进后出
            fun1();
            #endregion
        }
        //2、转换二进制
        public static void fun1()
        {
            Stack stack = new Stack();
            if(int.TryParse(Console.ReadLine(), out int num))
            {
                while(num != 0)
                {
                    stack.Push(num % 2);
                    num /= 2;
                    //Console.WriteLine(num);
                }
            }
            else
            {
                Console.WriteLine("输入错误");
            }
            foreach (object item in stack)
            {
                Console.WriteLine(item);
            }
        }
    }
}

三、Queue

using System.Collections;

namespace Lesson3_Queue
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 基础
            //1、本质是一个Object数组,2、封装了特殊的规则,3、先进先出。
            //使用需要声明命名空间System.Collections。
            //因为是object数组所以也存在装箱拆箱操作。
            #endregion
            #region 增
            Queue queue = new Queue();
            queue.Enqueue(1);
            queue.Enqueue(2);
            queue.Enqueue(3);
            #endregion
            #region 取
            object num = queue.Dequeue();
            Console.WriteLine("取:" + num);
            #endregion
            #region 查
            num = queue.Peek();//查看队列第一个元素
            Console.WriteLine("查:" + num);
            Console.WriteLine("包含:" + queue.Contains(1));//看是否包含该元素
            #endregion
            #region 改
            //只能先清空再增加
            queue.Clear();
            queue.Enqueue(1);
            queue.Enqueue(2);
            queue.Enqueue(3);
            #endregion
            #region 遍历
            //长度
            Console.WriteLine("长度:" + queue.Count);
            //foreach循环
            Console.WriteLine("foreach循环:");
            foreach (object item in queue)
            {
                Console.WriteLine(item);
            }
            //转换object数组
            Object[] objects = queue.ToArray();
            for(int i = 0; i < objects.Length; i++)
            {
                Console.WriteLine($"第{i}个元素为{objects[i]}");
            }
            //循环出栈
            while (queue.Count > 0)
            {
                Console.WriteLine($"取出{queue.Dequeue()}");
            }
            #endregion
            #region 队列的存储规则
            //先进先出,只能存一个,取一个。
            //定时打印消息
            Queue queue1 = new Queue();
            queue1.Enqueue("1111");
            queue1.Enqueue("2222");
            queue1.Enqueue("3333");
            queue1.Enqueue("4444");
            queue1.Enqueue("5555");
            queue1.Enqueue("6666");
            queue1.Enqueue("7777");
            queue1.Enqueue("8777");
            queue1.Enqueue("9777");
            queue1.Enqueue("10777");
            object[] objects1 = queue1.ToArray();
            int now = DateTime.Now.Second;
            int future;
            int count = 0;
            while (count < 10)
            {
                future = DateTime.Now.Second;
                if(future - now > 0.5)
                {
                    now = DateTime.Now.Second;
                    Console.WriteLine(objects1[count]);
                    count++;
                }
            }
            #endregion
        }
    }
}

四、Hashtable

using System.Collections;

namespace Lesson4_HashTable
{
    #region 练习二:怪物管理器
    class Monster
    {
        public string name;
        public Monster(string name)
        {
            this.name = name;
        }
    }
    class MonsterManager
    {
        Hashtable monsterTable;
        public MonsterManager()
        {
            monsterTable = new Hashtable();
        }
        public void CreateMonster(int id, Monster monster)
        {
            monsterTable.Add(id, monster);
        }
        public void RemoveMonster(int id)
        {
            monsterTable.Remove(id);
        }
        public void PrintMonter()
        {
            foreach(object item in monsterTable.Keys)
            {
                Console.WriteLine($"键为:{item},值为:{(monsterTable[item] as Monster).name}");
            }
        }
    }
    #endregion
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 基础
            //HashTable(又称散列表)是基于键的哈希代码组织起来的键值对。
            //主要作用是提高查询数据的效率
            //使用键来访问集合中的元素
            #endregion
            #region 声明
            //使用需要引用命名空间System.Collections
            Hashtable hashtable = new Hashtable();
            #endregion
            #region
            //不能出现相同的键
            hashtable.Add(1, 12);
            hashtable.Add(true, "123");
            #endregion
            #region 删除
            //只能删除不存在的键
            hashtable.Remove(true);
            //清空
            hashtable.Clear();
            #endregion
            #region
            //1、通过键来查看值,中括号中填入的是键值,而不是数组下标,找不到会返回空
            hashtable.Add(1, "1");
            hashtable.Add(2, "Hello");
            hashtable.Add("123", 123);
            hashtable.Add(123, "123");
            Console.WriteLine(hashtable[1]);
            //2、查看是否存在
            if (hashtable.Contains("123"))//或者使用ContainsKey也可以达到相同效果
            {
                Console.WriteLine(hashtable["123"]);
            }
            if (hashtable.ContainsValue(123))
            {
                Console.WriteLine("有");
            }
            #endregion
            #region
            //通过键去改
            hashtable[1] = "一";
            #endregion
            #region 遍历
            //得到键值对数量
            Console.WriteLine(hashtable.Count);
            //遍历键
            Console.WriteLine("遍历键");
            foreach(Object item in hashtable.Keys)
            {
                Console.Write("键:" + item);
                Console.WriteLine("  值:" + hashtable[item]);
            }
            //遍历值
            Console.WriteLine("遍历值");
            foreach (Object item in hashtable.Values)
            {
                Console.WriteLine(item);
            }
            //键值一起遍历
            Console.WriteLine("遍历键和值");
            foreach(DictionaryEntry item in hashtable)
            {
                Console.WriteLine(item.Key);
                Console.WriteLine(item.Value);
            }
            //迭代器循环
            Console.WriteLine("迭代器循环开始:");
            IDictionaryEnumerator dictionary = hashtable.GetEnumerator();
            bool flag = dictionary.MoveNext();
            while (flag)
            {
                Console.WriteLine("键为:" + dictionary.Key + ", 值为:" + dictionary.Value);
                flag = dictionary.MoveNext();
            }
            #endregion
            #region 练习一
            //请描述Hashtable的存储规则
            //Hashtable的存储规则是:存储键值对,键不可以重复。
            #endregion
            //测试练习二
            Monster m1 = new Monster("大大怪");
            MonsterManager monsterManager = new MonsterManager();
            monsterManager.CreateMonster(1, m1);
            monsterManager.PrintMonter();
        }
    }
}

五、泛型

  • 泛型实现了类型参数化,一份代码操作多种类型,达到代码复用。
  • 泛型相当于类型占位符,定义类或方法时使用替代符代表变量类型,使用时再指定具体类型。
  • 基本语法:
  • class 类名<泛型占位字母>
  • interface 接口名<泛型占位字母>
  • 泛型函数语法:
  • 函数名<泛型占位字母>(字母 名称)
  • 泛型占位字母可以有多个,用,号隔开。
using System.Runtime.InteropServices;
using System.Text;

namespace Lesson5_泛型
{
    class Common()
    {
        public string DetermineType<T>(T unknown)
        {
            Type type = unknown.GetType();
            switch (type.FullName)
            {
                case "System.Int32":
                    return $"整形,{Marshal.SizeOf(type)}字节";
                case "System.Char":
                    return $"字符,{Marshal.SizeOf(type)}字节";
                case "System.Single":
                    return $"字符,{Marshal.SizeOf(type)}字节";
                case "System.String":
                    string str = unknown as string;
                    return $"字符,{Encoding.UTF8.GetByteCount(str)}字节";
                default:
                    return "其他类型";
            }
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Common c1 = new Common();
            string str1 = c1.DetermineType<double>(4522);
            Console.WriteLine(str1);
        }
    }
}

六、泛型约束

  1. 是什么:用于限制泛型类型,共有6种类型:
类型格式
值类型where 泛型字母:struct
引用类型where 泛型字母:class
存在无参构造函数where 泛型字母:new()
某个类本身或者其派生类where 泛型字母:类名
某个接口的派生类型where 泛型字母:接口名
另一个泛型类型本身或者派生类型where 泛型字母:另一个泛型字母
  1. 约束直接可以联合使用,中间用","号隔开,一般new()是写在最后的。
  2. 对多个泛型约束,在后面再加where相关语句就行,并且两个where约束之间用空格隔开
namespace Lesson6_泛型约束
{
    #region 练习:实现单例模式基类
    class SingleBase<T> where T : new()
    {
        private static T instance = new T();
        
        public SingleBase()
        {

        }
        public static T Instance
        {
            get
            {
                return instance;
            }
        }
    }
    class Person : SingleBase<Person>
    {
        public int value;
    }
    #endregion
   
    internal class Program
    {
        static void Main(string[] args)
        {
            Person.Instance.value = 10;
        }
    }
}

七、List

using System.Collections.Generic;

namespace Lesson7_List
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 声明和基础
            //1.需要引用:using System.Collections.Generic;
            List<int> list = new List<int>();
            #endregion
            #region
            list.Add(1);
            //范围增加
            list.AddRange(list);
            //插入
            list.Insert(0, 2);
            #endregion
            #region
            //删除指定元素
            list.Remove(1);
            //删除指定位置元素
            list.RemoveAt(0);
            //清空
            list.Clear();
            #endregion
            #region
            list.Add(1);
            //查指定位置
            Console.WriteLine(list[0]);
            //是否存在某元素
            Console.WriteLine(list.Contains(1));
            //正向查找并返回位置,否则为-1
            Console.WriteLine(list.IndexOf(1));
            //反向查找
            Console.WriteLine(list.LastIndexOf(1));
            #endregion
            #region
            list[0] = 2;
            #endregion
            #region 遍历
            Console.WriteLine("长度:");
            Console.WriteLine(list.Count);
            Console.WriteLine("容量" + list.Capacity);
            //for遍历
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine($"第{i}个元素是:{list[i]}");
            }
            //foreach遍历
            foreach (int item in list)
            {
                Console.WriteLine(item);
            }
            #endregion
            #region 练习1:描述List和ArrayList的区别
            /* 1、list是泛型数组,不是object数组,所以需要指定类型,
             * 2、list不需要进行装箱拆箱。
             */
            #endregion
            #region 练习遍历、增、删
            List<int> ints = new List<int>();
            for (int i = 10; i > 0; i--)
            {
                ints.Add(i);
            }
            ints.RemoveAt(4);
            foreach (int item in ints)
            {
                Console.WriteLine(item);
            }
            #endregion
            #region 练习测试
            Boss boss = new Boss();
            Gablin g = new Gablin();
            foreach (Monster item in boss.Lists)
            {
                item.Attack();
            }
            #endregion
        }
    }
    #region 遍历怪物类产生攻击
    class Monster
    {
        private static List<Monster> lists = new List<Monster>();

        public Monster()
        {
            lists.Add(this);
        }
        public List<Monster> Lists
        {
            get
            {
                return lists;
            }
        }
        public void Attack()
        {
            Console.WriteLine(this + "的攻击");
        }
    }
    class Boss : Monster
    {

    }
    class Gablin : Monster
    {

    }
    #endregion
}

八、Dictionary

namespace Lesson8_Dectionary
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 声明和基础
            //需要引入命名空间 System.Collection.Generic
            //Dectionary是需要制定类型的键值对。
            Dictionary<int, string> d = new Dictionary<int, string>();
            #endregion
            #region
            //单个增加,不能有重复键
            d.Add(1, "123");
            #endregion
            #region
            //根据键来删除
            d.Remove(1);
            //清空
            d.Clear();
            #endregion
            #region
            //根据键查询,没找到会报错
            d.Add(1, "111");
            Console.WriteLine(d[1]);
            //根据键或值判断是否存在
            Console.WriteLine(d.ContainsKey(1));
            Console.WriteLine(d.ContainsValue("1"));
            #endregion
            #region
            //根据查的方法来改
            d[1] = "1111111";
            #endregion
            #region 遍历
            d.Add(2, "22222222");
            d.Add(5, "555555555");
            d.Add(4, "4444444444444444");
            //遍历键,顺便遍历值
            foreach (int item in d.Keys)
            {
                Console.WriteLine("键是:" + item + ",值是:" + d[item]);
            }
            //遍历值
            //将d.Keys改为Values即可

            //一起遍历
            foreach (KeyValuePair<int, string> item in d)
            {
                Console.WriteLine("键是:" + item.Key + ",值是:" + item.Value);
            }
            #endregion
            //练习1测试
            ConvertInput();
            //练习2
            Dictionary<char, int> dic = new Dictionary<char, int>();
            string str = "Hello";
            foreach (char i in str)
            {
                if (dic.ContainsKey(i))
                {
                    dic[i]++;
                }
                else
                {
                    dic.Add(i, 1);
                }
            }
            foreach(KeyValuePair<char, int> pair in dic)
            {
                Console.WriteLine("键:" + pair.Key + ", 值:" + pair.Value);
            }
        }
        #region 练习1:使用字典存储大写字
        static void ConvertInput()
        {
            string str = "";
            Console.WriteLine("请输入1~3位数");  // 先输出提示
            string input = Console.ReadLine();  // 获取用户输入
                                                // 可选:添加输入验证
            if (input.Length > 0 && input.Length <= 3)
            {
                Dictionary<int, string> d = new Dictionary<int, string>
                    {
                        {1, "壹"},
                        {2, "贰"},
                        {3, "叁"},
                        {4, "肆"},
                        {5, "伍"},
                        {6, "陆"},
                        {7, "柒"},
                        {8, "捌"},
                        {9, "玖"}
                    };
                char[] chars = input.ToCharArray();
                for (int i = 0; i < chars.Length; i++)
                {
                    switch (chars[i])
                    {
                        case '1':
                            str += '壹';
                            break;
                        case '2':
                            str += '贰';
                            break;
                        case '3':
                            str += '叁';
                            break;
                        case '4':
                            str += '肆';
                            break;
                        case '5':
                            str += '伍';
                            break;
                        case '6':
                            str += '陆';
                            break;
                        case '7':
                            str += '陆';
                            break;
                        case '8':
                            str += '捌';
                            break;
                        case '9':
                            str += '玖';
                            break;
                    }
                }
            }
            else
            {
                Console.WriteLine("输入不符合要求");
            }
            Console.WriteLine(str);
        }
        #endregion
    }
}

九、顺序存储和链式存储

namespace Lesson9_顺序存储和链式存储
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 常用的数据结构
            //有1、栈 2、队列 3、数组 4、图 5、链表 6、树 7、堆 8、散列表
            #endregion
            #region 顺与链的区别
            //顺序存储内存地址是按顺序排列的,连续的;链式则是随机的
            #endregion
            //双向链表测试
            LikeList<int> likeList = new LikeList<int>();
            likeList.Add(1);
            Console.WriteLine("个数:" + likeList.Count());
            likeList.Remove(1);
            Console.WriteLine("个数:" + likeList.Count());
        }
    }
    #region 双向链表
    class Node<T>
    {
        public T data;
        public Node<T> prev;
        public Node<T>? next;
        public Node(T data)
        {
            this.data = data;
        }
    }
    class LikeList<T>
    {
        Node<T>? head;
        Node<T>? last;
        public int Count()
        {
            if (head == null) return 0;
            Node<T> current = head;
            int count = 0;
            while(current != null)
            {
                Console.WriteLine(current.data);
                count++;
                current = current.next;
            }
            return count;
        }
        public void Add(T data)
        {
            if(head == null)
            {
                head = new Node<T>(data);
                last = head;
            }
            else if(last == head && head != null)
            {
                last = new Node<T>(data);
                head.next = last;
                last.prev = head;
            }
            else
            {
                last.next = new Node<T>(data);
                last.next.prev = last;
                last = last.next;
            }
        }
        public void Remove(T data)
        {
            if (head == null) return;
            if (head.data.Equals(data))
            {
                if (head == last)
                {
                    head = null;
                    last = null;
                }
                else
                {
                    head.next.prev = null;
                    head = head.next;
                }
            }
            else if (last.data.Equals(data))
            {
                if (head == last)
                {
                    head = null;
                    last = head;
                }
                else
                {
                    last = last.prev;
                    last.next = null;
                }
            }
            else
            {
                Node<T> current = head.next;
                while (current != null)
                {
                    if (current.data.Equals(data))
                    {
                        current.prev.next = current.next;
                        current.next.prev = current.prev;
                        return;
                    }
                    current = current.next;
                }
            }    
        }
    }
    #endregion
}

十、LinkedList

using System.Collections.Generic;

namespace Lesson10_LinkedList
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 基础
            //本质是一个泛型双向链表
            LinkedList<int> ints = new LinkedList<int>();
            //需要掌握LinkedList和LinkedListNode两个类
            #endregion
            #region 增
            //尾部加
            ints.AddLast(1);
            //头部加
            ints.AddFirst(2);
            //在某节点前加,第一个值是寻找的节点,第二个值是新加数据的值
            LinkedListNode<int> listNode = ints.Find(2);
            ints.AddBefore(listNode, 10);
            ints.AddAfter(listNode, 11);
            #endregion
            #region 删
            //移除头
            ints.RemoveFirst();
            //移除尾部
            ints.RemoveLast();
            //移除指定数据节点
            ints.Remove(1);
            //清空
            ints.Clear();
            #endregion
            #region 查
            ints.AddLast(1);
            //查头、尾节点
            LinkedListNode<int> node = ints.First;
            node = ints.Last;
            //查找指定数据节点
            node = ints.Find(1);
            Console.WriteLine(node.Value);
            //判断是否存在
            ints.Contains(1);
            #endregion
            #region 改
            //需要先得到再改
            node.Value = 20;
            #endregion
            #region 遍历
            //foreach遍历
            Console.WriteLine("----------");
            ints.AddLast(2);
            ints.AddLast(214);
            foreach (int item in ints)
            {
                Console.WriteLine(item);
            }
            #endregion
            //遍历节点,也可以将ints.First改为ints.Last,这样就是从尾到头遍历。
            LinkedListNode<int> temp = ints.First;
            while(temp != null)
            {
                Console.WriteLine(temp.Value);
                temp = temp.Next;
            }
            #region 练习
            Console.WriteLine("练习开始:----------------");
            //加入10个变量
            LinkedList<int> list = new LinkedList<int>();
            list.AddLast(89);
            list.AddFirst(22);
            list.AddBefore(list.Find(22), 10);
            list.AddAfter(list.First, 82);
            list.AddLast(781);
            list.AddLast(1111);
            list.AddLast(33);
            list.AddLast(03);
            list.AddLast(53);
            list.AddLast(41);
            list.Clear();
            Random r = new Random();
            for(int i = 0; i < 10; i++)
            {
                list.AddLast(r.Next(1, 3));
            }
            //遍历
            foreach(int item in list)
            {
                Console.WriteLine(item);
            }
            //反向遍历
            Console.WriteLine("反向遍历开始:----------");
            temp = list.Last;
            while(temp != null)
            {
                Console.WriteLine(temp.Value);
                temp = temp.Previous;
            }
            #endregion
        }
    }
}

十一、总结容器与泛型栈、泛型队列

namespace Lesson11_泛型栈和队列
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 接触过的容器
            /*值类型:
             * 无符号的
             * 1字节  2字节    4字节   8字节
             * byte   ushort   uint    ulong
             * 有符号的
             * 1字节  2字节    4字节   8字节
             * sbyte  short    int     long
             * 4字节  8字节    16字节
             * float  double   decimal
             * 2字节  1字节
             * char   bool
             * enum   struct
             */
            /*引用类型:
             * string object interface class等
             */
            /*Object型集合
             * ArrayList object数据列表
             * Stack 栈 先进后出
             * Queue 队列 先进先出
             * Hashtable 哈希表,键值对
             */
            /*泛型数组
             * List 泛型列表
             * Dictionary  泛型键值对
             * LinkedList 泛型链表
             * Stack 泛型栈
             * Queue 泛型队列
             */
            #endregion
            #region 泛型栈、队列
            Stack<int> s = new Stack<int>();
            Queue<Object> q = new Queue<object>();
            #endregion
        }
    }
}

十二、委托

namespace Lesson12_委托
{
    //委托可以用于将一系列方法按顺序加入,再之后触发。
    delegate void MyFun1();
    delegate void MyFun2<T>(T value);
    delegate int MyFun3();
    delegate void MyFun4(int i);
    //委托不能重名,也不能重载
    //存入的方法必须格式一致

    //委托常用法:在类中使用,并在委托中可执行其他操作
    class Test
    {
        MyFun1 m1;
        MyFun4 m4;
        public void test1(MyFun1 m1, MyFun4 m4)
        {
            this.m1 = m1;
            this.m4 = m4;
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 委托基本概念
            //委托是函数的容器可以理解为函数的变量类型
            //关键字:delegate
            //修饰符 delegate 返回值 委托名(参数列表);
            //一般是写在namespace中,也能写在class中
            //默认为public
            #endregion
            //存入委托
            MyFun1 f10 = new MyFun1(Fun);
            //直接调用
            f10.Invoke();
            //存入委托第二种方法:
            MyFun1 f11 = Fun;
            //调用
            f11();
            MyFun2<int> f21 = Fun2;
            f21(5);
            Test t = new Test();
            t.test1(Fun, Fun2);
            //存入多个函数
            MyFun4 mf4 = Fun2;
            mf4 += Fun2;
            //移除函数
            mf4 -= Fun2;
            mf4(50);
            //清空
            mf4 = null;
            mf4 += Fun2;
            //mf4 -= Fun2;
            //mf4 -= Fun2;
            mf4(1);

            #region 系统提供的委托
            Action action = Fun;//无参无返回值委托
            Func<int> fint = Fun3;//返回值为泛型的无参委托
            Action<int> astring = Fun2;//参数(最多16个参数)为泛型无返回值类型。
            Func<int, int> fint1;//<参数类型(最多16个 ,返回值类型 >最后一个为返回值类型。
            //Action 管理无返回值委托。参数可0到16
            //Func 管理有返回值, 也可有参数的类型,参数可以0到16。
            #endregion
            #region 练习1:模拟一家人吃饭
            Action<string> aFamily1 = MakeFood;
            Action<string, string> aFamily2 = PrepareFood;
            Action<string, string, string> aFamily3 = EatFood;
            aFamily1("Mother");
            aFamily2("Mother", "Child");
            aFamily3("Mother", "Child", "Father");
            #endregion
            #region 练习2:模拟击杀怪物
            //更好的逻辑是:在怪物类中添加委托并把加钱、更新、增加成就三个方法加入其中,在死亡时触发委托。
            Action<int> AddMoney = Fun2;
            Action UpdateUI = Fun;
            Action<int> AddNum = Fun2;
            AddMoney(10);
            UpdateUI();
            AddNum(1);
            #endregion
        }
        static void MakeFood(string m)
        {
            Console.WriteLine(m + "在做饭");
        }
        static void PrepareFood(string m, string c)
        {
            Console.WriteLine($"{m}{c}开饭");
        }
        static void EatFood(string m, string c, string f)
        {
            Console.WriteLine($"{m}{c}{f}开饭");
        }
        public static void Fun()
        {
            Console.WriteLine("委托测试");
        }
        static void Fun2(int v)
        {
            Console.WriteLine(v);
        }
        static int Fun3()
        {
            return 3;
        }
    }
}

十三、事件

using System.Security.Cryptography;

namespace Lesson13_事件
{
    class Test
    {
        #region 事件是什么
        //事件是基于委托的存在,是一种特殊的变量类型
        //事件是委托的安全包裹,让委托使用更具有安全性
        #endregion
        #region 事件声明和使用
        //事件的声明和使用,事件不能再类外部声明,赋值,调用。
        //事件的使用和委托一样
        //事件不能作为临时变量在函数中声明
        //事件的作用:防止外部随意声明空委托,防止随意调用委托。
        /*总结:
         * 事件与委托区别:事件是特殊委托,事件不能再外部使用= 和 声明,委托可以。
         * 事件不能再外部执行,委托可以。
         * 事件不能作为临时变量,委托可以。
         */
        #region 练习1:热水器
        event Action hot;
        int temperature;
        public void UseHot()
        {
            temperature = 0;
            hot = AddHot;
            hot += WarnHot;
            hot += ShowHot;
            hot();
        }
        public void AddHot()
        {
            Console.WriteLine("加热");
            int i = 0;
            while (true)
            {
                if (i % 9999999 == 0)
                {
                    temperature++;
                }
                i++;
                if (temperature > 100) return;
            }
        }
        public void WarnHot()
        {
            if(temperature > 95)
            {
                Console.WriteLine("95摄氏度了");
            }
        }
        public void ShowHot()
        {
            Console.WriteLine("水开了");
        }
        #endregion
        public event Action Ac;
        public Test()
        {
            Ac = Fun1;
            Ac += Fun1;
            Ac -= Fun1;
            Ac();
        }
        #endregion
        public static void Fun1()
        {
            Console.WriteLine("Fun1"); 
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Test t = new Test();
            t.UseHot();
        }
    }
}

十四、匿名函数

namespace Lesson14_匿名函数
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 什么是匿名函数
            //匿名函数是没有名字的函数。
            //匿名函数必须配合委托和事件使用。
            //匿名函数无法除去,只能= null来清空。
            #endregion
            #region 基础语法
            /*delegate (参数列表)
             * {
             *      //语句
             *  }
             *  何时使用?
             *  1.函数中传递委托参数时
             *  2.委托或事件赋值时
             */
            //使用:
            Action action = delegate ()
            {
                Console.WriteLine("你好");
            };
            action();
                //有参函数
            Action<int> action1 = delegate (int a)
            {
                Console.WriteLine($"{a}你好");
            };
            action1(1);
                //有返回值
            Func<int> func = delegate ()
            {
                return 8;
            };
            Console.WriteLine(func());
            //使用场景:
            //1、参数传递
            TestClass tc = new TestClass();
            tc.Test1(delegate ()
            {
                Console.WriteLine("Test1");
            });
            //2、返回值传递
            Action a = tc.Test2();
            //或者
            tc.Test2()();
            #endregion
            Console.WriteLine(tc.Cale(5)(4));
        }
    }
    class TestClass
    {
        public void Test1(Action action)
        {
            action();
        }
        public Action Test2()
        {
            return delegate ()
            {
                Console.WriteLine("Test2");
            };
        }
        public Func<int, int> Cale(int x)
        {
            return delegate (int y)
            {
                return x * y;
            };
        }
    }
}

十五、lambad表达式

namespace Lesson15_lambad表达式
{
    internal class Program
    {
        #region 练习题
        static Action ac;
        static Action Test()
        {
            for(int i = 1; i < 11; i++)
            {
                int index = i;
                ac += () =>
                    {
                        Console.WriteLine(index);
                    };
            }
            return ac;
        }
        #endregion
        static void Main(string[] args)
        {
            #region 什么是lambad表达式
            //
            /*语法:
             * (参数列表) => {
             *      语句;
             * };
             */
            #endregion
            #region 使用
            //无参无返回值
            Action action = () =>
            {
                int i = 1;
                Console.WriteLine(i);
            };
            //可以省略形参类型
            Action<int> action1 = (value) =>
            {
                Console.WriteLine(value);
            };
            Fun2();
            #endregion
            action = Test();
            action();
        }
        static event Action action2;
        //闭包:内层使用外层的变量,延长了变量生命周期
        static void Fun1()
        {
            int i = 1;
            action2 = () =>
                {
                    Console.WriteLine(i);
                };
            action2();
            i++;
            action2();
        }
        static void Fun2()
        {
            Fun1();
            action2();
        }
    }
}

十六、List排序

namespace Lesson16_List排序
{
    //7、练习
    #region 练习
    //对怪物类进行排序
    class Monster1
    {
        public int atk;
        public int def;
        public int hp;
        public Monster1(int atk, int def, int hp)
        {
            this.atk = atk;
            this.def = def;
            this.hp = hp;
        }
    }
    #endregion
    //3、自定义继承并实现方法
    class Item : IComparable<Item>
    {
        public int money;
        public Item(int money)
        {
            this.money = money;
        }

        public int CompareTo(Item? other)
        {
            //大于0则将当前对象放在传入other对象后面
            if (this.money > other.money)
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
    }
    class Monster
    {
        public int id;
        public Monster(int id)
        {
            this.id = id;
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 1、List自带排序
            //list.Sort();在ArrayList中也有这个方法。
            List<int> ints = new List<int>();
            ints.Add(2);
            ints.Add(4);
            ints.Add(90);
            ints.Add(1);
            foreach (int item in ints)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("-------------");
            ints.Sort();
            foreach (int item in ints)
            {
                Console.WriteLine(item);
            }
            #endregion
            #region 2、自定义排序
            //类的排序  需要继承IComparable
            Console.WriteLine("-----自定义排序---------");
            List<Item> items = new List<Item>();
            items.Add(new Item(100));
            items.Add(new Item(29));
            items.Add(new Item(4));
            items.Add(new Item(8));
            items.Add(new Item(25));
            items.Add(new Item(19));
            items.Sort();//验证自定义Item类排序
            foreach (Item item1 in items)
            {
                Console.WriteLine(item1.money);
            }
            Console.WriteLine("--------重载自定义排序------------");
            List<Monster> mls = new List<Monster>();
            mls.Add(new Monster(123));
            mls.Add(new Monster(45));
            mls.Add(new Monster(5));
            mls.Add(new Monster(79));
            mls.Add(new Monster(22));
            //5、还能用lambad表达式来写匿名函数。
            //mls.Sort((m1, m2) =>
            //{
            //    if (m1.id > m2.id)
            //    {
            //        return 1;
            //    }
            //    else
            //    {
            //        return -1;
            //    }
            //});
            mls.Sort((m1, m2) => { return m1.id > m2.id ? 1 : -1; });//6、运用lambad表达式和三目运算符
            //mls.Sort(Compare)//重载方法测试
            foreach (Monster ml in mls)
            {
                Console.WriteLine(ml.id);
            }
            //8、练习测试
            List<Monster1> mons = new List<Monster1>();
            for (int i = 0; i < 10; i++)
            {
                mons.Add(new Monster1(10 + i, 5 + i, 10 + i * 5));
            }
            Console.WriteLine("开始练习测试");
            int playerNum = Console.Read();
            Console.WriteLine($"你输入的是:{playerNum}");
            if (playerNum == 1)
            {
                mons.Sort((m1, m2) => { return m1.atk > m2.atk ? 1 : -1; });
            }
            else if(playerNum == 2)
            {
                mons.Sort((m1, m2) => { return m1.def > m2.def ? 1 : -1; });
            }
            else if (playerNum == 3)
            {
                mons.Sort((m1, m2) => { return m1.hp > m2.hp ? 1 : -1; });
            }
            else if(playerNum == 4)
            {
                int num;
                List<Monster1> temp1 = new List<Monster1>();
                for(int i = 0; i < mons.Count; i++)
                {
                    num = mons.Count - i - 1;    
                    temp1.Add(mons[num]);
                }
                mons = temp1;
                foreach (Monster1 item in mons)
                {
                    Console.WriteLine(item.atk);
                }
            }
            else
            {
                Console.WriteLine("请重新输入");
            }
            #endregion
            //4、自定义重载方法:需要利用Sort的重载方法传入一个排序方法
            static int Compare(Monster m1, Monster m2)
            {
                if (m1.id > m2.id)
                {
                    return 1;
                }
                else
                {
                    return -1;
                }
            }
        }
    }
}

十七、协变逆变

image.png

#region 作用:
//参数和返回值
delegate void Go<in T>(T t);
delegate T Fly<out T>();
interface Test1<out T>
{
    T Fun1();
}
#endregion
//结合里式替换原则进行
TestOut<Son> os = () =>
{
    return new Son();
};
TestOut<Father> of = os;
Father father = of();
TestIn<Father> If = (f) => {};
TestIn<Son> Is = If;
Is(new Son());

image.png

十八、多线程

image.png

image.png

 //注意:声明的lock锁的判定变量必须是引用类型
    internal class Program
    {
        static bool isRun = true;
    delegate void Customize();
    static void Main(string[] args)
    {
        Customize customize = () =>
        {
            Console.WriteLine("OK1");
        };
        Thread td1 = new Thread(new ThreadStart(customize));
        Thread td2 = new Thread(() => { Console.WriteLine("OK2"); });
        Thread td3 = new Thread(FunWhile);
        //开启线程
        td1.Start();
        td2.Start();
        td3.Start();
        //设置成后台线程,受主线程
        td1.IsBackground = true;
    //1、需要再主程序中控制线程是否关闭,可以加如bool标识来控制。
        //isRun = false;
    //2、中止程序
        //td3.Abort();//已经废弃
        //td3 = null;
    }
    static void FunWhile()
    {
        while (isRun)
        {
            Console.WriteLine("循环3");
            //线程休眠
            Thread.Sleep(2000);
        }
    }
            static object conlock = new object();
            static void Main(string[] args)
            {
                Thread thread = new Thread(Fun1);
                thread.Start();
                while (true)
                {
                    lock(conlock){
                        Console.SetCursorPosition(0, 0);
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("*");
                    }
                }
            }
            static void Fun1()
            {
                while (true)
                {
                    lock (conlock)
                    {
                        Console.SetCursorPosition(10, 0);
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("□");
                    }
                }
            }
        }

十九、预处理器指令

image.png

//定义符号
#define unity4
//取消符号
#undef unity4
namespace L36_预处理器指令
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //if处理,判断有没有该符号,有则会被编译;还能加||和&&
            #if unity4
                Console.WriteLine("Hello");  
            #elif unity4
                Console.WriteLine("123")
            #else
                Console.WriteLine("456");
            #endif
            //警告和错误
            #warning 不好
            #error 出错啦
        }
    }
}

image.png

二十、反射概念和关键类Type

image.png

image.png

image.png

image.png

image.png

image.png

需要引入命名空间using System.Reflection;

# region 获取公共构造函数
//获取所有公共构造函数
ConstructorInfo[] constructors = t2.GetConstructors();
foreach(ConstructorInfo con in constructors)
{
    Console.WriteLine(con);
}
//得到构造函数传入 Type数组 数组中按顺序是参数类型
//执行构造函数,传入object数组,按顺序是参数
//无参构造
ConstructorInfo info = t2.GetConstructor(new Type[0]);
Console.WriteLine(info);
Test test2 = info.Invoke(null) as Test;
Console.WriteLine(test2.y);
//有参构造
ConstructorInfo info1 = t2.GetConstructor(new Type[] {typeof(int)});
Test test1 = info1.Invoke(new object[] { 3 }) as Test;
Console.WriteLine(test1.x);
#endregion
#region 获取公共成员变量
//获取所有公共成员变量
Console.WriteLine("获取所有公共成员变量----");
FieldInfo[] fieldInfo = t.GetFields();
for (int i = 0; i < fieldInfo.Length; i++)
{
    Console.WriteLine(fieldInfo[i]);
}
//得到指定变量
FieldInfo field = t.GetField("x");
Console.WriteLine(field);
//获取变量值
object obj = info.Invoke(null);
object tempNum = field.GetValue(obj);
Console.WriteLine($"tempNum:{tempNum}");
//设置变量值
field.SetValue(obj, 10);
Console.WriteLine("x:" + field.GetValue(obj));
#endregion
#region 获取公共成员方法
//获取所有公共成员方法
Console.WriteLine("公共成员方法------");
Type type = typeof(int);
MethodInfo[] methods = type.GetMethods();
for (int i = 0; i < methods.Length; i++)
{
    Console.WriteLine($"methods[{i}]: {methods[i]}");
}
//得到公共成员方法
MethodInfo method = type.GetMethod("Parse", new Type[] { typeof(string) });
//使用(注意,第一个参数是哪个对象要执行,如果是静态方法传入null)
int num = (int)method.Invoke(null, new object[] {"123"});
Console.WriteLine("num类型是:" + num);
#endregion

二十一、反射关键类Activator和Assembly

image.png

    #region Activator
    Console.WriteLine("----Activator----");
    //用于快速实例化对象的类
    Type acType = typeof(Test);
    //实例化无参
    Test acTest = Activator.CreateInstance(acType) as Test;
    Console.WriteLine(acTest.x);
    //有参构造
    Test acTest1 = Activator.CreateInstance(acType, 12) as Test;
    Console.WriteLine(acTest1.x);
    #endregion

    #region Assembly
    Console.WriteLine("-------Assembly----------");
    //加载指定程序集
    Assembly assembly = 
    Assembly.LoadFrom(@"E:\temp\Csharp\CSharp进阶\L36_预处理器指令\bin\Debug\net8.0\L36_预处理器指令");
    Type[] types = assembly.GetTypes();
    foreach (Type item in types)
    {
        Console.WriteLine(item);
    }
    //加载其中一个类,填写命名空间.类名(注意:如果没写在命名空间中,前面不填)
    Console.WriteLine("-----使用加载物中的类-----");
    Type type1 = assembly.GetType("TestMonster");
    MemberInfo[] memberInfo = type1.GetMembers();
    for (int i = 0; i < memberInfo.Length; i++)
    {
        Console.WriteLine(memberInfo[i]);
    }
    //获取枚举
    Type type2 = assembly.GetType("E_Type");
    MemberInfo[] E_infos = type2.GetMembers();
    Console.WriteLine("-----打印枚举信息------");
    foreach (MemberInfo item in E_infos)
    {
        Console.WriteLine(item);
    }
    FieldInfo ty1 = type2.GetField("type1");
    //使用TestMonster带有枚举的构造方法
    object tm = Activator.CreateInstance(type1, ty1.GetValue(null), 5, 10);
    Console.WriteLine("----打印传入字符-------");
    MethodInfo methodInfo = type1.GetMethod("Hello", new Type[] {typeof(string)});
    //传入对象是实例对象, 和参数
    methodInfo.Invoke(tm, new object[] {"你好"});
    #endregion

二十二、特性

image.png image.png image.png 英语生词:usage:使用。Targets:目标。Multiple:倍数,多个。Inherited:继承的。Attribute:属性。

namespace L43_特性
{
    //为特性添加特性的限制
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
    class MyCustomAttribute : Attribute
    {
        public string Name { get; set; }
        public MyCustomAttribute(string name)
        {
            Name = name;
        }
    }
    //类或其他元数据上写特性,[特性名(参数)]
    [MyCustom("你好,这是一个测试类")]
    [MyCustom("世界")]
    public class MyTest
    {
        public void PrintStr([MyCustom("变量特性")] string str)
        {

        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Type t = Type.GetType("L43_特性.MyTest");
            //判断是否使用了该特性 参数一:特性类型,并参数二:查找父类是否使用了。
            if (t.IsDefined(typeof(MyCustomAttribute), false))
            {
                Console.WriteLine("使用了该特性");
            }
            //获取并打印
            object[] Attributes = t.GetCustomAttributes(true);
            foreach (object attr in Attributes)
            {
                Console.WriteLine((attr as MyCustomAttribute).Name);
            }
        }
    }
}

image.png 英语生词:Obsolete:过时的。

image.png 英语生词:Caller:呼叫者

public class MyTest
{
    [Obsolete("该方法已经过时啦----")]
    public void PrintStr([MyCustom("变量特性")] string str, [CallerFilePath] string x = "")
    {
        Console.WriteLine($"{str}{x}");
    }
}
在主函数中输出:
MyTest test = new MyTest();
test.PrintStr("123");

image.png 英语生词:Conditional:有条件的。define:定义

在最上方:
#define Fun
public class MyTest
{
    [Conditional("Fun")]
    public void Fun()
    {
        Console.WriteLine("Fun输出");
    }
}
在主函数中:
MyTest test = new MyTest();
test.Fun();

image.png

image.png

二十三、迭代器

image.png

image.png

using System.Collections;

namespace L23_迭代器
{
    class Level : IEnumerator, IEnumerable
    {
        int[] arr;
        //用于计数的下标
        int nextIndex;
        public Level()
        {
            arr = new int[] { 9, 6, 3, 10, 21 };
            nextIndex = -1;
        }
        //获取当前值
        public object Current
        {
            get
            {
                return arr[nextIndex];
            }
        }
        public IEnumerator GetEnumerator()
        {
            return new Level();
        }
        //用于判断下一位置是否有值
        public bool MoveNext()
        {
            nextIndex++;
            return nextIndex < arr.Length;
        }
        //一般用于重置光标
        public void Reset()
        {
            throw new NotImplementedException();
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Level level = new Level();
            foreach(int i in level)
            {
                Console.WriteLine(i);
            }
            foreach (int i in level)
            {
                Console.WriteLine(i);
            }
        }
    }
}

image.png

class MonsterLevel : IEnumerable
{
    int[] arrs = { 9, 6, 3, 1 };
    public MonsterLevel()
    {

    }
    public MonsterLevel(int[] arrs)
    {
        this.arrs = arrs;
    }
    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < arrs.Length; i++) {
            yield return arrs[i];
        }
    }
}

image.png

二十四、特殊语法

image.png

知识二:初始化

class Monster
{
    int money;
    public string name;
    public int id
    {
        get; set;
    }
    public Monster(int id) {
        this.id = id;
    }
}
internal class Program
{
    static void Main(string[] args)
    {
        Monster monster = new Monster(2) { name = "123"};
        Console.WriteLine(monster.name + monster.id);
    }
}

image.png 知识四:匿名类型

var con = new {name = "战士"};
Console.WriteLine(con.name);

知识五:可空类型

#region 知识五:可空类型
//值类型不能为空。但在类型后面加?可以赋值为null
int? x = null;
//判断是否为空,空就不进入
if (x.HasValue)
{
    Console.WriteLine("进入");
    Console.WriteLine(x.Value);
}
//安全获取可空类型:为空返回该类型默认值,也可后面给值返回,不会将给的值赋值给获取变量
Console.WriteLine(x.GetValueOrDefault(100));
//调用是判断是否为空,不为空就输出
string str = "测试";
Console.WriteLine(str?.ToString());
int[] ints = null;
Console.WriteLine(ints?.Length);
#endregion

image.png

Console.WriteLine(str ?? "1223");

image.png

image.png

二十五、值和引用类型


image.png


image.png


image.png


image.png

image.png


image.png


image.png

TestStruct(结构体)、ITest(接口)在1中打印 1 1 2 因为在栈中声明变量会新开一个房间用于存放而2中因为存在装箱将栈转换为堆中,所以打印99