首页 > 编程语言 >C#--进阶

C#--进阶

时间:2024-03-15 15:58:07浏览次数:15  
标签:Console 进阶 C# System -- int WriteLine using public

CSharp进阶知识点学习

知识点汇总

简单数据结构类:

Lesson1:ArrayList

练习:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson1_练习
{

    #region 练习一
    //请简述ArrayList 和 数组的区别

    //1.ArrayList本质上是一个object数组的封装
    //2.数组可以指定存储类型,ArrayList默认为object类型
    //3.数组的增删查改需要我们自己去实现,ArrayList帮我们封装好了方便的API来使用
    //4.ArrayList使用时可能存在装箱拆箱,数组使用时只要不是object数组就不存在这个问题
    //5.数组长度用Length,ArrayList长度用Count

    #endregion

    #region 练习二
    //创建一个背包管理类,使用ArrayList存储物品
    //实现购买物品,卖出物品,显示物品的功能,购买与卖出物品会导致金钱变化

    class BagMgr
    {
        //背包中的物品
        private ArrayList items;

        private int money;

        public BagMgr(int money)
        {
            this.money = money;
            items = new ArrayList();
        }

        //买物品
        public void BuyItem(Item item)
        {
            //避免乱传
            if (item.num <= 0 || item.money < 0)
            {
                Console.WriteLine("请传入正确的物品信息。");
                return;
            }

            if (money < item.money * item.num)
            {
                Console.WriteLine("买不起,钱不够。");
                return; 
            }

            //若是钱够就减钱
            money -= item.money * item.num;
            Console.WriteLine("购买了{0},共{1}个花费了{2}元",item.name, item.num, item.money*item.num);
            Console.WriteLine("剩余{0}钱",money);

            //如果想要叠加物品 可以在前面先判断 是否有这个物品 然后加数量
            for (int i = 0; i < items.Count; i++)
            {
                if ((items[i] as Item).id == item.id)
                {
                    (items[i] as Item).num += item.num;
                    return;
                }
            }
            //把一组物品加到 list中
            items.Add(item);
        }

        //卖出物品
        public void SellItem(Item item)
        {
            for (int i = 0; i < items.Count; i++)
            {
                //如何判断 卖的东西背包里有没有
                //这是在判断 两个引用地址 指向的是不是同一个房间地址
                //所以我们要判断 卖的物品 一般不这样判断
                //if ((items[i] as Item) == item)
                //{

                //}

                if ((items[i] as Item).id == item.id)
                {
                    //两种情况 
                    int num = 0;
                    string name = (items[i] as Item).name;
                    int money = (items[i] as Item).money;
                    if ((items[i] as Item).num > item.num)
                    {
                        //1.比我身上的少
                        num = item.num;
                        (items[i] as Item).num -= num;
                    }
                    else
                    {
                        //2.大于等于我身上的东西数量 
                        num = (items[i] as Item).num;
                        //卖完了就移除
                        items.RemoveAt(i);
                    }

                    int sellMoney = (int)(num * money * 0.8f);
                    money += sellMoney;

                    Console.WriteLine("卖出去了{0},共{1}个,赚了{2}元钱", name, num, sellMoney);
                    Console.WriteLine("目前拥有{0}元钱",money);

                    return;

                }

            }
            
        }

        public void SellItem(int id, int num)
        {
            //调用一下上面的方法
            Item item = new Item(id, num);
            SellItem(item);
        }

        public void SellItem(string name)
        {

        }

        //显示物品
        public void ShowItem()
        {
            Item item;
            for (int i = 0; i < items.Count; i++)
            {
                item = items[i] as Item;
                Console.WriteLine("{0}    {1}个", item.name, item.num);
            }
            Console.WriteLine("当前拥有{0}元钱", money);
        }
    }

    class Item
    {
        //物品唯一ID 来区分物品的种类
        public int id;
        //物品值多少钱(表示单价)
        public int money; 
        //物品名字
        public string name;
        //物品数量
        public int num;

        public Item(int id, int num)
        {
            this.id = id;
            this.num = num;
        }

        public Item(int id, int money, string name, int num)
        {
            this.id = id;
            this.money = money;
            this.name = name;
            this.num = num;
        }

    }

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("ArrayList练习");

            BagMgr bag = new BagMgr(99999);
            Item i1 = new Item(1, 10, "痛苦面具", 10);
            Item i2 = new Item(2, 20, "三圣之力", 5);
            Item i3 = new Item(3, 666, "狂徒铠甲", 8);

            bag.BuyItem(i1);
            bag.BuyItem(i2);
            bag.BuyItem(i3);

            bag.SellItem(i2);

            bag.SellItem(3, 2);
            bag.SellItem(3, 3);

            bag.ShowItem();

        }
    }
}

Lesson2:Stack

练习:

Lesson3:Queue(队列)

练习:

Lesson4:Hashtable

练习:

用到了单例模式

泛型:

Lesson5:泛型

练习:

Lesson6:泛型约束

练习:

常用泛型数据结构类

Lesson7:List

练习:

Lesson8:Dictionary

练习:

Lesson9:顺序存储和链式存储

知识点六 顺序存储和链式存储的优缺点

练习:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson9_练习
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("顺序存储和链式存储练习");

            #region 练习一
            //请说出常用的数据结构有哪些
            //数组、栈、队列、树、链表、散列表、堆、图
            #endregion

            #region 练习二
            //请描述顺序存储和链式存储的区别
            //顺序存储:内存中用一组地址连续的存储单元存储线性表(连续地址存储)
            //链式存储:内存中用一组任意的存储单元存储线性表(任意地址存储)
            #endregion

            #region 练习三
            //请尝试自己实现一个双向链表
            //并提供以下方法和属性
            //数据的个数,头节点,尾节点
            //增加数据到链表最后
            //删除指定位置节点

            LinkedList<int> list = new LinkedList<int>();
            list.Add(1);
            list.Add(2);
            list.Add(3);
            list.Add(4);
            list.Add(5);

            //从头遍历
            LinkedNode<int> node = list.Head;
            for (int i = 0; i < list.Num; i++)
            {
                Console.WriteLine(node.value);
                node = node.nextNode;
            }

            Console.WriteLine("=======================");

            //从尾遍历
            node = list.Last;
            for (int i = 0; i < list.Num; i++)
            {
                Console.WriteLine(node.value);
                node = node.frontNode;
            }

            Console.WriteLine("=======================");

            list.Remove(2);
            node = list.Head;
            for (int i = 0; i < list.Num; i++)
            {
                Console.WriteLine(node.value);
                node = node.nextNode;
            }

            Console.WriteLine("=======================");

            list.Remove(0);
            node = list.Head;
            for (int i = 0; i < list.Num; i++)
            {
                Console.WriteLine(node.value);
                node = node.nextNode;
            }

            Console.WriteLine("=======================");

            list.Remove(3);
            node = list.Head;
            for (int i = 0; i < list.Num; i++)
            {
                Console.WriteLine(node.value);
                node = node.nextNode;
            }

            #endregion


        }
    }

    /// <summary>
    /// 双向列表节点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class LinkedNode<T>
    {
        public T value;
        //存储上一个是谁
        public LinkedNode<T> frontNode;
        //存储下一个是谁
        public LinkedNode<T> nextNode;

        public LinkedNode(T value)
        {
            this.value = value;
        }
    }

    /// <summary>
    /// 双向链表类 管理节点 管理添加
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class LinkedList<T>
    {
        private int num = 0;
        private LinkedNode<T> head;
        private LinkedNode<T> last;

        public int Num
        {
            get
            {
                return num;
            }
        }

        public LinkedNode<T> Head
        {
            get
            {
                return head;
            }
        }

        public LinkedNode<T> Last
        {
            get
            {
                return last;
            }
        }

        public void Add(T value)
        {
            LinkedNode<T> node = new LinkedNode<T>(value);
            if (head == null)
            {
                head = node;
                last = node;
            }
            else
            {
                //添加到尾部
                last.nextNode = node;
                //尾部添加记入上一个节点是谁
                node.frontNode = last;
                //让当前添加的变成最后一个节点
                last = node;
            }

            ++num;
        }

        public void Remove(int num)
        {
            //首先判断有没有越界
            if (this.num - 1 < num || num < 0)
            {
                Console.WriteLine("不存在这个位置的值");
                return;
            }
            int temp = 0;
            LinkedNode<T> tempNode = head;
            while (true)
            {
                if (temp == num)
                {
                    //找到了,移除即可
                    //当前要移除的节点的上一个节点 指向自己的下一个节点
                    if (tempNode.frontNode != null)
                    {
                        tempNode.frontNode.nextNode = tempNode.nextNode;
                    }
                    if (tempNode.nextNode != null)
                    {
                        tempNode.nextNode.frontNode = tempNode.frontNode;
                    }
                    //如果是头节点需要改变头节点的指向
                    if (num == 0)
                    {
                        //如果头结点被移除 那头节点就变成了头节点的下一个
                        head = tempNode.nextNode;
                    }
                    else if(num == this.num - 1)
                    {
                        //如果尾节点被移除了,那么尾节点就变成了尾节点的上一个
                        last = last.frontNode;
                    }

                    --this.num;
                    break;
                }
                ++temp;
                tempNode = tempNode.nextNode;
            }
        }
    }

}

Lesson10:LinkedList

练习:

重点:

Lesson11:泛型栈和队列

练习:
数组、List、Dictionary、Stack、Queue、LinkedList
这些存储容器,对于我们来说应该如何选择?

委托和事件

Lesson12:委托

练习:

Lesson13:事件

事件和委托的区别

Lesson14:匿名函数

练习:

Lesson15:Lambad表达式

补充知识点:

练习:

List排序

Lesson16:List排序

练习:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson16_练习
{

    #region 练习一
    //写一个怪物类,创建10个怪物将其添加到List中
    //对List列表进行排序,根据用户输入数字进行排序
    //1.攻击排序
    //2.防御排序
    //3.血量排序
    //4.反转

    class Monster : IComparable<Monster>
    {
        public int atk;
        public int enk;
        public int hp;
        public int id;

        public Monster(int atk, int enk, int hp, int id)
        {
            this.atk = atk;
            this.enk = enk;
            this.hp = hp;
            this.id = id;
        }

        //继承接口的排序方法
        public int CompareTo(Monster other)
        {
            //升序
            if (this.atk > other.atk)
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
    }

    #endregion

    #region 练习二
    //写一个物品类(类型、名字、品质),创建10个物品
    //添加到List中
    //同时使用类型、品质、名字长度进行比较
    //排序的权重是:类型>品质>名字长度

    class Item
    {
        public int type;
        public string name;
        public int quality;

        public Item(int type, string name, int quality)
        {
            this.type = type;
            this.name = name;
            this.quality = quality;
        }

        public override string ToString()
        {
            return string.Format("道具信息:类型:{0},名字:{1},品质:{2}", type, name, quality);
        }
    }

    #endregion

    #region 练习三
    //涉及到 : linq  SQL

    //尝试利用List排序方式对Dictionary中的内容排序
    //提示:得到Dictionary的所有键值对信息存入List中
    #endregion


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("List排序练习");

            #region 练习一
            Console.WriteLine("================  练习一  ===================");
            List<Monster> m = new List<Monster>();
            m.Add(new Monster(5, 1, 9, 1));
            m.Add(new Monster(4, 2, 8, 2));
            m.Add(new Monster(3, 1, 7, 3));
            m.Add(new Monster(2, 4, 3, 4));
            m.Add(new Monster(3, 8, 3, 5));
            m.Add(new Monster(8, 7, 5, 6));
            m.Add(new Monster(4, 1, 7, 7));
            m.Add(new Monster(7, 2, 6, 8));
            m.Add(new Monster(2, 9, 6, 9));
            m.Add(new Monster(6, 4, 7, 10));

            Console.WriteLine("请输入1~3:");
            int num = int.Parse(Console.ReadLine());

            try
            {
                if (num == 1)
                {
                    //继承接口的方式
                    m.Sort();
                    Console.WriteLine("攻击力升序排序:");
                    for (int i = 0; i < m.Count; i++)
                    {
                        Console.WriteLine("怪物:{0},攻击力为:{1}", m[i].id, m[i].atk);
                    }
                }
                else if (num == 2)
                {
                    //调用方法--泛型的方式
                    m.Sort(Test);
                    Console.WriteLine("防御力降序排序:");
                    for (int i = 0; i < m.Count; i++)
                    {
                        Console.WriteLine("怪物:{0},防御力为:{1}", m[i].id, m[i].enk);
                    }
                }
                else if (num == 3)
                {
                    //匿名函数的方法  升序
                    //m.Sort(delegate (Monster m1, Monster m2)
                    //{
                    //    return m1.hp > m2.hp ? 1 : -1;
                    //});
                    //lambad  降序
                    m.Sort((m1, m2) => { return m1.hp > m2.hp ? -1 : 1; });
                    Console.WriteLine("血量升序排序:");
                    for (int i = 0; i < m.Count; i++)
                    {
                        Console.WriteLine("怪物:{0},血量为:{1}", m[i].id, m[i].hp);
                    }
                }
                else if (num == 4)
                {
                    m.Reverse();
                    Console.WriteLine("反转打印");
                    for (int i = 0; i < m.Count; i++)
                    {
                        Console.WriteLine("怪物:{0}", m[i].id);
                    }
                }
            }
            catch
            {
                Console.WriteLine("请输入数字!");
            }
            #endregion

            #region 练习二
            Console.WriteLine("================  练习二  ===================");
            List<Item> itemList = new List<Item>();
            Random r = new Random();
            for (int i = 0; i < 10; i++)
            {
                itemList.Add(new Item(r.Next(1, 6), "Item" + r.Next(1, 201), r.Next(1, 6)));
                Console.WriteLine(itemList[i]);
            }

            itemList.Sort((a, b) =>
            {
                //类型不同 按类型比
                if (a.type != b.type)
                {
                    return a.type > b.type ? -1 : 1;
                }
                //品质不同 按品质比
                else if (a.quality != b.quality)
                {
                    return a.quality > b.quality ? -1 : 1;
                }
                //否则就直接按名字长度比
                else
                {
                    return a.name.Length > b.name.Length ? -1 : 1;
                }
            });

            Console.WriteLine("=========================");

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(itemList[i]);
            }
            #endregion

            #region 练习三
            Console.WriteLine("================  练习三  ===================");
            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic.Add(1, "123456");
            dic.Add(4, "123456");
            dic.Add(3, "123456");
            dic.Add(7, "123456");
            dic.Add(5, "123456");
            dic.Add(9, "123456");

            List<KeyValuePair<int, string>> list = new List<KeyValuePair<int, string>>();

            foreach (KeyValuePair<int, string> item in dic)
            {
                list.Add(item);
                Console.WriteLine(item.Key + "--" + item.Value);
            }

            list.Sort((a, b) =>
            {
                return a.Key > b.Key ? 1 : -1;
            });

            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i].Key + "--" + list[i].Value);
            }

            #endregion


        }



        static int Test(Monster m1, Monster m2)
        {
            //降序
            if (m1.enk > m2.enk)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        }

    }
}

协变逆变

Lesson17:协变和逆变

练习:
请描述协变逆变有什么作用

多线程

Lesson18:多线程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Lesson18_多线程
{
    class Program
    {

        static bool isRuning = true;

        static object obj = new object();

        static void Main(string[] args)
        {
            Console.WriteLine("多线程");

            #region 知识点一 了解线程前先了解进程
            //进程(Process)是计算机中的程序关于某数据集合上的一次运行活动
            //是系统进行资源分配和调度的基本单位,是操作系统结构的基础
            //说人话:打开一个应用程序就是在操作系统上开启了一个进程
            //进程之间可以相互独立运行,互不干扰
            //进程之间也可以相互访问、操作
            #endregion

            #region 知识点二 什么是线程
            //操作系统能够进行运算调度的最小单位
            //它被包含在进程之中,是进程中的实际运作单位
            //一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程
            //我们目前写的程序 都在主线程中

            //简单理解线程:
            //就是代码从上到下运行的一条“管道"
            #endregion

            #region 知识点三 什么是多线程
            //我们可以通过代码 开启新的线程
            //可以同时运行代码的多条“管道”就叫多线程
            #endregion

            #region 知识点四 语法相关
            //线程类 Thread
            //需要引用命名空间 using System.Threading;
            //1.申明一个新的线程
            //  注意 线程执行的代码 需要封装到一个函数中
            //  新线程 将要执行的代码逻辑 被封装到了一个函数语句块中
            Thread t = new Thread(NewThreadLogic);

            //2.启动线程
            t.Start();

            //3.设置为后台线程
            //当前台线程都结束的时候,整个程序也就结束了,即使还有后台线程正在运行
            //后台线程不会防止应用程序的进程被终止掉
            //如果不设置为后台线程 可能导致进程无法正常关闭
            t.IsBackground = true;

            //4.关闭释放一个线程
            //如果开启的线程中不是死循环 是能够结束的逻辑 那么 不用刻意的去关闭它
            //如果是死循环 想要终止这个线程 有两种方式
            //4.1--死循环中bool标识
            //Console.ReadKey();

            //isRuning = false;

            //Console.ReadKey();

            //4.2--通过线程提供的方法(注意在.Net core版本中无法中止 会报错)
            //try
            //{
            //    //终止线程
            //    t.Abort();
            //    t = null;
            //}
            //catch
            //{

            //}

            //5.线程休眠
            //让线程休眠多少毫秒  1s = 1000毫秒
            //在哪个线程里执行 就休眠哪个线程
            //Thread.Sleep(1000);

            #endregion

            #region 知识点五 线程之间共享数据
            //多个线程使用的内存是共享的,都属于该应用程序(进程)
            //所以要注意 当多线程 同时操作同一片内存区域时可能会出现问题
            //可以通过加锁的形式避免问题

            //lock
            //当我们在多个线程当中想要访问同样的东西 进行逻辑处理时
            //为避免不必要的逻辑顺序执行的查错
            //lock(引用类型对象)

            while (true)
            {
                lock (obj)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write("●");
                }
                
            }

            #endregion

            #region 知识点六 多线程对于我们的意义
            //可以用多线程专门处理一些复杂耗时的逻辑
            //比如 寻路、网络通信等等
            #endregion

        }

        static void NewThreadLogic()
        {
            //新开线程 执行的代码逻辑 在该函数语句块中
            while (isRuning)
            {
                //Thread.Sleep(1000);
                //Console.WriteLine("新开线程代码逻辑。");

                lock (obj)
                {
                    Console.SetCursorPosition(10, 5);
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write("■");
                }
                
            }
            
        }


        //总结
        //多线程是多个可以同时执行代码逻辑的“管道”
        //可以通过代码开启多线程,用多线程处理一些复杂的可能影响主线程流畅度的逻辑
        //关键字: Thread

    }
}

练习:

预处理器指令

Lesson19:预处理器指令

//定义一个符号
#define Unity4
#define Unity5
//#define Unity2017
#define Unity2019
//取消定义一个符号
#undef Unity4

#define IOS
#define Android
#define PC

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson19_预处理器指令
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("预处理器指令");

            #region 知识点一 什么是编译器
            //编译器是一种翻译程序
            //它用于将源语言程序翻译为目标语言程序

            //源语言程序:某种程序设计语言写成的,比如C#、C、C++、Java等语言写的程序
            //目标语言程序:二进制数表示的伪机器代码写的程序
            #endregion

            #region 知识点二 什么是预处理器指令
            //预处理器指令 指导编译器 在实际编译开始前对信息进行预处理
            //预处理器指令 都是以# 开始
            //预处理器指令不是语句,所以它们不以分号 ; 结束
            //目前我们经常用到 折叠代码块 就是预处理器指令
            #endregion

            #region 知识点三 常见的预处理器指令
            //1
            //#define
            //定义一个符号,类似一个没有值的变量
            //#undef
            //取消define定义的符号,让其失效
            //两者都是写在脚本文件最前面
            //一般配合 if指令使用 或配合特征

            //2
            //#if
            //#elif
            //#else
            //#endif
            //和if语句规则一样,一般配合#define定义的符号使用
            //用于告诉编译器进行编译代码的流程控制

            //如果发现有Unity4这个符号 那么其中包含的代码 就会被编译器翻译
            //可以通过 逻辑或 和 逻辑与 进行多种符号的组合判断
#if Unity4
            Console.WriteLine("版本为Unity4");
#elif Unity2017 || IOS
            Console.WriteLine("版本为Unity2017");
            //#warning 这个版本 不合法
            //#error 这个版本不支持执行
#else
            Console.WriteLine("其他版本");
#endif

            //3
            //#warning
            //#error
            //告诉编译器
            //是警报还是报错误
            //一般还是配合if使用

            #endregion


            //总结
            //预处理器指令 
            //可以让代码还没有编译之前就可以进行一些预处理判断
            //在Unity中会用来进行一些平台或者版本的判断
            //决定不同的版本或者不同的平台使用不同的代码逻辑

        }
    }
}

练习:
#define Unity5
#define Unity2017
#define Unity2020
#undef Unity2017
#undef Unity5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lesson19_练习
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("预处理器指令练习");

            #region 练习一
            //请说出至少4种预处理器指令
            //1.#define  定义一个符号 (没有值的变量)
            //  #undef   取消定义一个符号

            //2.#if
            //  #elif
            //  #else
            //  #endif

            //3.#warning
            //  #error

            #endregion

            #region 练习二
            //请使用预处理器指令实现
            //写一个函数计算两个数
            //当是Unity5版本时算加法
            //当是Unity2017版本时算乘法
            //当是Unity2020版本是算减法
            //都不是返回0

            Console.WriteLine(Test(10,20));


            #endregion

        }

        static int Test(int x, int y)
        {
#if Unity5
            int sam = x + y;
            return sam;
#elif Unity2017
            int sam = x * y;
            return sam;
#elif Unity2020
            int sam = x - y;
            return sam;
#else 
            return 0;

#endif
        }

    }
}

反射和特性

Lesson20:反射

练习:

注意:路径最后加上后缀,不然会报错,暂时我也不知道为什么不加会报错

Lesson21:特性

#define Fun
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Lesson21_特性
{

    #region 知识点一 特性是什么
    //特性是一种允许我们向程序的程序集添加元数据的语言结构
    //它是用于保持程序结构信息的某种特殊类型的类

    //特性提供功能强大的方法以将申明信息与 C# 代码(类型、方法、属性等)相关联。
    //特性与程序实体关联后,即可在运行时使用反射查询特性信息

    //特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集中
    //它可以放置在几乎所有的申明中(类、变量、函数等等申明)

    //说人话:
    //特性本质是个类
    //我们可以利用特性类为元数据添加额外信息
    //比如一个类、成员变量、成员方法等等为它们添加更多的额外信息
    //之后可以通过反射来获取这些额外信息
    #endregion

    #region 知识点二 自定义特性
    //继承特性基类 Attribute
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
    class MyCustomAttribute : Attribute
    {
        //特性中的成员 一般根据需求来写
        public string info;

        public MyCustomAttribute(string info)
        {
            this.info = info;
        }

        public void TestFun()
        {
            Console.WriteLine("特性的方法");
        }
    }
    #endregion

    #region 知识点三 特性的使用
    //基本语法:
    //[特性名(参数列表)]
    //本质上 就是在调用特性的构造函数
    //写在哪里?
    //类、函数、变量上一行,表示他们具有该特性信息

    [MyCustom("这个是自己写的一个用于计算的类")]
    [MyCustom("这个是自己写的一个用于计算的类")]
    class MyClass
    {
        [MyCustom("这是一个成员变量")]
        public int value;

        //[MyCustom("这是一个用于计算加法的函数")]
        //public void TestFun([MyCustom("函数参数")]int a)
        //{

        //}
        public void TestFun(int a)
        {

        }

    }

    #endregion

    #region 知识点四 限制自定义特性的使用范围
    //通过为特性类 加特性 限制其使用范围
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = true)]
    //参数一:AttributeTargets -- 特性能够用在哪些地方
    //参数二:AllowMultiple -- 是否允许多个特性实例用在同一个目标上
    //参数三:Inherited -- 特性是否能被派生类和重写成员继承

    public class MyCustom2Attribute : Attribute
    {

    }
    #endregion

    #region 知识点五 系统自带特性--过时特性
    //过时特性
    //Obsolete
    //用于提示用户 使用的方法等成员已经过时 建议使用新方法
    //一般加在函数前的特性

    class TestClass
    {
        //参数一:调用过时方法时 提示的内容
        //参数二:true--使用该方法时会报错  false--使用该方法时直接警告
        [Obsolete("OldSpeak方法已经过时了,请使用Speak方法", false)]
        public void OldSpeak(string str)
        {
            Console.WriteLine(str);
        }

        public void Speak()
        {

        }

        public void SpeakCaller(string str, [CallerFilePath]string fileName = "", 
            [CallerLineNumber]int line = 0, [CallerMemberName]string target = "")
        {
            Console.WriteLine(str);
            Console.WriteLine(fileName);
            Console.WriteLine(line);
            Console.WriteLine(target);
        }

    }

    #endregion

    #region 知识点六 系统自带特征 -- 调用者信息特征
    //哪个文件调用?
    //CallerFilePath特性
    //哪一行调用
    //CallerLineNumber特性
    //哪个函数调用?
    //CallerMemberName特性

    //需要引用命名空间 using System.Runtime.CompilerServices;
    //一般作为函数参数的特性
    #endregion

    #region 知识点七 系统自带特性 -- 条件编译特性
    //条件编译特性
    //Conditional
    //它会和预处理指令 #define配合使用

    //需要引用命名空间using System.Diagnostics;
    //主要可以用在一些调试代码上
    //有时想执行有时不想执行的代码
    #endregion

    #region 知识点八 系统自带特性--外部Dll包函数特性
    //DllImport

    //用来标记非.Net(C#)的函数,表明该函数在一个外部的DLL中定义
    //一般用来调用 C 或者 C++ 的DLL包写好的方法
    //需要引用命名空间 using System.Runtime.InteropServices
    #endregion


    class Program
    {

        [DllImport("Test.dll")]
        public static extern int Add(int a, int b);

        [Conditional("Fun")]
        static void Fun()
        {
            Console.WriteLine("Fun执行");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("特性");

            #region 特性的使用
            MyClass mc = new MyClass();
            Type t = mc.GetType();
            //t = typeof(MyClass);
            //t = Type.GetType("Lesson21_特性.MyClass");

            //判断是否使用了某个特性
            //参数一:特性的类型
            //参数二:代表是否搜索继续
            if (t.IsDefined(typeof(MyCustomAttribute), false))
            {
                Console.WriteLine("该类型应用了MyCustom特性");
            }

            //获取Type元数据中的所有特性
            object[] array = t.GetCustomAttributes(true);
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i] is MyCustomAttribute)
                {
                    Console.WriteLine((array[i] as MyCustomAttribute).info);
                    (array[i] as MyCustomAttribute).TestFun();
                }
            }

            TestClass tc = new TestClass();
            tc.OldSpeak("123");
            tc.Speak();

            tc.SpeakCaller("123456");

            Fun();

            #endregion


            //总结
            //特性是用于 为元数据再添加更多的额外信息(变量、方法等等)
            //我们可以通过反射获取这些额外的数据 来进行一些特殊的处理
            //自定义特性--继承Attribute类

            //系统自带特性:过时特性

            //为什么要学习特性
            //Unity引擎中许多地方都用到了特性来进行一些特殊处理

        }
    }
}

练习:

Lesson22:迭代器

练习:

Lesson23:特殊语法

Lesson24:值和引用

排序进阶

面试时会考,但后面开发不常用

建议面试时突击复习下就可以!

Lesson25:插入排序

Lesson26:希尔排序

暂时学到这,剩余排序进阶的知识后面再学!

总结

毋庸置疑C#进阶的知识点挺重要,要多回来复习学习!

接下来的任务是把C#进阶的实践小项目《俄罗斯方块》做完,然后进入Unity的学习!

抓紧时间!!!

标签:Console,进阶,C#,System,--,int,WriteLine,using,public
From: https://blog.csdn.net/SunsetSunup/article/details/135469524

相关文章

  • 进程守护
    #!/bin/shdeclare-Amodules=(["gateway"]="zt-gateway"["auth"]="zt-auth"["site"]="zt-modules-site"["system"]="zt-modules-system"["chip"]="zt-modules-chip&qu......
  • PHP引用序列化漏洞
    介绍根据php引用的特性构造序列化漏洞示例<?phpclassjust4fun{var$enter;var$secret;}$hxdyjx=newjust4fun();$hxdyjx->enter=&$hxdyjx->secret;echoserialize($hxdyjx);构造<?phpclassjust4fun{var$enter;var$secret;}$hxdy......
  • MIT 6.S081入门lab7 多线程
    MIT6.S081入门lab7多线程一、参考资料阅读与总结1.xv6book书籍阅读(Chapter7:SchedulingthroughSection7.4)1.概述:由于操作系统往往运行比CPU数量更多的进程,因此需要对CPU进行虚拟化,使多个进程能够分时复用CPU资源2.多路复用:xv6中多路复用有2种方式:sleep和wakeup机制......
  • 超轻量级的c#版基于文件的日志记录工具,可定制输出格式,可指定日志文件
    这是我自己个人编写的日志记录,主要使用在只需要记录日志,偶尔到文件中查看一下日志记录的情况。我自己写的一些服务之类的是使用了这个的,代码很少,使用很简单。第一步搜索和安装我的Nuget包搜索和安装zmjtool这个包,我写的,如下图:第二步引入namespace和创建logger对象1/**引......
  • SourceTree提示Authentication failed for 如何解决
    sourcetree拉取失败提示Authenticationfailed(下图)1、关闭sourcetree;2、打开文件目录C:\Users\****\AppData\Local\Atlassian\SourceTree,删除passwd文件;3、打开sourcetree,点击拉取,就会弹出身份验证窗口,输入完成点击login即可拉取成功; ......
  • 使用JWT进行授权认证
    .Net6WebAPI中1、安装组件(Nuget)Microsoft.AspNetCore.Authentication.JwtBearer2、Program.cs配置//授权认证(使用JWT)builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o=>{//私钥varsecretByte=Encoding.UTF8.GetBytes......
  • 如何快速删除excel中多行中的空行
    作为一个Excel专家,处理数据时经常需要删除空行。以下是一些快速删除多行中空行的方法:方法一:使用筛选功能选中数据区域:首先,使用鼠标或键盘快捷键选中包含空行的多行数据区域。应用筛选:在Excel的“数据”标签页中,点击“筛选”按钮。此时,数据区域的每个列标题旁都会出现一个小......
  • Python下Django通过SSHTunnel连接ECS上未开通外网地址RDS的解决方案
    在开发过程中,碰到需要在PythonDjango项目中连接到位于ECS上但未开通外网地址的RDS数据库。这种情况下,通过建立SSH隧道来实现连接,确保数据传输的安全性和可靠性。 1、安装sshtunnel包pip3installsshtunnel2、导入SSHTunnelFowarder模块fromsshtunnelimp......
  • 【力扣】目标和(新鲜的01背包题)
    题目描述分析01背包的题做起来最难的是把原问题转化成01背包题,通常需要写出题目中所有的数学关系,对公式进行化简后得到01背包的类型。在这种情景下还需要重新定义dp数组的含义于是连带的。dp数组的递推公式也要重新想大胆的按照五步骤结合题目分析的话其实并不是难到无......
  • ffmpeg多路视频合并
    2,3,4路视频拼接可以参考下面:https://blog.csdn.net/tianshan2010/article/details/104737576https://blog.csdn.net/Gary__123456/article/details/887427054路拼接【上下左右】:ffmpeg-i1.mp4-i2.mp4-i3.mp4-i4.mp4-filter_complex"[0:v]pad=iw2:ih2[a];[a][1:v]ove......