当前位置: 首页 > news >正文

C#每日学习日记

委托

 知识点一 委托是什么
    委托是 函数(方法)的容器 
    可以理解为表示函数(方法)的变量类型
    用来 存储、传递函数(方法)
    委托的本质是一个类,用来定义函数(方法)的类型返回值和参数的类型
    不同的 函数(方法)必须对应和各自"格式"一致的委托
 

知识点二 基本语法
    关键字 : delegate
    语法:

访问修饰符 delegate 返回值 委托名(参数列表);

    写在哪里?
    可以申明在namespace和class语句块中
    更多的写在namespace中

    简单记忆委托语法 就是 函数申明语法前面加一个delegate关键字
 

知识点三 定义自定义委托
    访问修饰默认不写 为public 在别的命名空间中也能使用
    private 其它命名空间就不能用了
    一般使用public

    申明了一个可以用来存储无参无返回值函数的容器
    这里只是定义了规则 并没有使用
    delegate void MyFun();
    委托规则的申明 是不能重名(同一语句块中)
    表示用来装载或传递 返回值为int 有一个int参数的函数的 委托 容器规则
    public delegate int MyFun2(int a);

    委托是支持 泛型的 可以让返回值和参数 可变 更方便我们的使用
    delegate T MyFun3<T, K>(T v, K k);
 

知识点四 使用定义好的委托
    委托变量是函数的容器    委托常用在:
    1.作为类的成员
    2.作为函数的参数

    class Test{public MyFun fun;public MyFun2 fun2;public Action action;public void TestFun( MyFun fun, MyFun2 fun2 ){//先处理一些别的逻辑 当这些逻辑处理完了 再执行传入的函数int i = 1;i *= 2;i += 2;//fun();//fun2(i);//this.fun = fun;//this.fun2 = fun2;}#region 增public void AddFun(MyFun fun, MyFun2 fun2){this.fun += fun;this.fun2 += fun2;}#endregion#region 删public void RemoveFun(MyFun fun, MyFun2 fun2){//this.fun = this.fun - fun;this.fun -= fun;this.fun2 -= fun2;}#endregion}#endregion

知识点五 委托变量可以存储多个函数(多播委托)


 

   class Program{static void Main(string[] args){Console.WriteLine("委托");//专门用来装载 函数的 容器MyFun f = new MyFun(Fun);Console.WriteLine("1");Console.WriteLine("2");Console.WriteLine("3");Console.WriteLine("4");Console.WriteLine("5");f.Invoke();MyFun f2 = Fun;Console.WriteLine("1");Console.WriteLine("2");Console.WriteLine("3");Console.WriteLine("4");Console.WriteLine("5");f2();MyFun2 f3 = Fun2;//注意:这里使用的是方法组转换(method group conversion),也就是简写形式,自动匹配方法签名。Console.WriteLine(f3(1));MyFun2 f4 = new MyFun2(Fun2);Console.WriteLine(f4.Invoke(3));Test t = new Test();t.TestFun(Fun, Fun2);Console.WriteLine("***************");//如何用委托存储多个函数MyFun ff = null;//ff = ff + Fun;ff += Fun;ff += Fun3;ff();//从容器中移除指定的函数ff -= Fun;//多减 不会报错 无非就是不处理而已ff -= Fun;ff();//清空容器ff = null;if( ff != null ){ff();}           }static void Fun(){Console.WriteLine("张三做什么");}static void Fun3(){Console.WriteLine("李四做什么");}static string Fun4(){return "";}static int Fun5(){return 1;}static void Fun6(int i, string s){}static int Fun2(int value){return value;}}

     

知识点六 系统定义好的委托
            使用系统自带委托 需要引用using System;
            无参无返回值
            Action action = Fun;
            action += Fun3;
            action();

            可以指定返回值类型的 泛型委托
            Func<string> funcString = Fun4;
            Func<int> funcInt = Fun5;

            可以传n个参数的  系统提供了 1到16个参数的委托 直接用就行了
            Action<int, string> action2 = Fun6;

            可以传n个参数的 并且有返回值的 系统也提供了 16个委托
            Func<int, int> func2 = Fun2;
 

   

总结
    简单理解 委托 就是装载、传递函数的容器而已
    可以用委托变量 来存储函数或者传递函数的
    系统其实已经提供了很多委托给我们用 
    Action:没有返回值,参数提供了 0~16个委托给我们用
    Func:有返回值,参数提供了 0~16个委托给我们用

委托本质上是一个 函数指针的封装体,它可以把方法当作参数进行传递或赋值。

  • 回调函数(Callback)

  • 事件机制(Event)

  • 策略模式(Strategy Pattern)

  • 组合多个方法执行(多播委托)

 

List排序

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Lesson16_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;
            }
        }
    }

    class ShopItem
    {
        public int id;

        public ShopItem(int id)
        {
            this.id = id;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("List排序");
            #region 知识点一 List自带排序方法
            List<int> list = new List<int>();
            list.Add(3);
            list.Add(2);
            list.Add(6);
            list.Add(1);
            list.Add(4);
            list.Add(5);
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i]);
            }
            list提供了排序方法
            list.Sort();
            Console.WriteLine("**************");
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i]);
            }
            ArrayList中也有Sort排序方法
            #endregion

            #region 知识点二 自定义类的排序
            List<Item> itemList = new List<Item>();
            itemList.Add(new Item(45));
            itemList.Add(new Item(10));
            itemList.Add(new Item(99));
            itemList.Add(new Item(24));
            itemList.Add(new Item(100));
            itemList.Add(new Item(12));
            排序方法
            itemList.Sort();
            for (int i = 0; i < itemList.Count; i++)
            {
                Console.WriteLine(itemList[i].money);
            }
            #endregion

            #region 知识点三 通过委托函数进行排序
            List<ShopItem> shopItems = new List<ShopItem>();
            shopItems.Add(new ShopItem(2));
            shopItems.Add(new ShopItem(1));
            shopItems.Add(new ShopItem(4));
            shopItems.Add(new ShopItem(3));
            shopItems.Add(new ShopItem(6));
            shopItems.Add(new ShopItem(5));

            //shopItems.Sort(SortShopItem);
            匿名函数
            //shopItems.Sort(delegate (ShopItem a, ShopItem b)
            //{
            //    if (a.id > b.id)
            //    {
            //        return -1;
            //    }
            //    else
            //    {
            //        return 1;
            //    }
            //});
            lambad表达式 配合 三目运算符的 完美呈现
            shopItems.Sort((a, b) =>{ return a.id > b.id ? 1 : -1;});

            Console.WriteLine("*********************");
            for (int i = 0; i < shopItems.Count; i++)
            {
                Console.WriteLine(shopItems[i].id);
            }
            #endregion
        }

        static int SortShopItem( ShopItem a, ShopItem b )
        {
            传入的两个对象 为列表中的两个对象
            进行两两的比较  用左边的和右边的条件 比较
            返回值规则 和之前一样 0做标准 负数在左(前) 正数在右(后)

            if (a.id > b.id)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        }
    }

    总结
    系统自带的变量(int,float,double.....) 一般都可以直接Sort
    自定义类Sort有两种方式
    1.继承接口 IComparable
    2.在Sort中传入委托函数

}
 

协变逆变 

知识点一 什么是协变逆变
    协变:
    和谐的变化,自然的变化
    因为 里氏替换原则 父类可以装子类
    所以 子类变父类  
    比如 string 变成 object 
    感受是和谐的

    逆变:
    逆常规的变化,不正常的变化
    因为 里氏替换原则 父类可以装子类 但是子类不能装父类
    所以 父类变子类  
    比如 object 变成 string
    感受是不和谐的

    协变和逆变是用来修饰泛型的
    协变:out 
    逆变:in

    用于在泛型中 修饰 泛型字母的 
    只有泛型接口和泛型委托能使用
 

知识点二 作用
   

1.返回值 和 参数
    用out修饰的泛型 只能作为返回值
    delegate T TestOut<out T>();
    用in修饰的泛型 只能作为参数
    delegate void TestIn<in T>(T t);

   
2.结合里氏替换原则理解

    class Father{}class Son:Father{}class Program{static void Main(string[] args){Console.WriteLine("协变逆变");#region 知识点二 作用(结合里氏替换原则理解)//协变 父类总是能被子类替换// 看起来 就是 son ——> fatherTestOut<Son> os = () =>{return new Son();};TestOut<Father> of = os;Father f = of();//实际上 返回的 是os里面装的函数 返回的是Son//逆变 父类总是能被子类替换//看起来像是 father——>son 明明是传父类 但是你传子类 不和谐的TestIn<Father> iF = (value) =>{};TestIn<Son> iS = iF;iS(new Son());//实际上 调用的是 iF#endregion}}

    总结


    协变 out
    逆变 in

    用来修饰 泛型替代符的  只能修饰接口和委托中的泛型

    作用两点
    1.out修饰的泛型类型 只能作为返回值类型 in修饰的泛型类型 只能作为 参数类型
    2.遵循里氏替换原则的  用out和in修饰的 泛型委托 可以相互装载(有父子关系的泛型)

      协变  父类泛型委托装子类泛型委托    逆变 子类泛型委托装父类泛型委托
}
 

 

http://www.lryc.cn/news/581352.html

相关文章:

  • NumPy-核心函数np.matmul()深入解析
  • Windows内存泄漏自动化
  • 大数据学习2:HIve
  • 关于 JNI 函数逆向(从 Java 到 native)
  • WebAssembly国际化多语种支持
  • .NET9 实现斐波那契数列(FibonacciSequence)性能测试
  • 闲庭信步使用SV搭建图像测试平台:第三十二课——系列结篇语
  • 力扣 hot100 Day35
  • 详解存储单位、内存寻址及数据存储方式
  • stm32达到什么程度叫精通?
  • jxWebUI--前端联动计算
  • Linux内核深度解析:IPv4策略路由的核心实现与fib_rules.c源码剖析
  • Spring boot之身份验证和访问控制
  • Day52 神经网络调参指南
  • Policy Gradient【强化学习的数学原理】
  • elementui表格增加搜索功能
  • 供应链管理学习笔记4-供应链网络设计
  • 【MySQL进阶】错误日志,二进制日志,mysql系统库
  • 每日算法刷题Day42 7.5:leetcode前缀和3道题,用时2h
  • Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算
  • WPF学习笔记(25)MVVM框架与项目实例
  • Kali Linux Wifi 伪造热点
  • LLM:位置编码详解与实现
  • 通过 Windows 共享文件夹 + 手机访问(SMB协议)如何实现
  • Git 版本控制完全指南:从入门到精通
  • 2025年3月青少年电子学会等级考试 中小学生python编程等级考试三级真题答案解析(判断题)
  • 如何解决Spring Boot中@Valid对List校验失效问题
  • Kafka消息积压的多维度解决方案:超越简单扩容的完整策略
  • 南山科技园的步行
  • LangChain:向量存储和检索器(入门篇三)