当前位置: 首页 > 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.dtcms.com/a/267095.html

相关文章:

  • 3dmax烘焙插件3dmax法线贴图烘焙教程glb和gltf元宇宙灯光效果图烘焙烘焙光影贴图支持VR渲染器
  • AWS WebRTC:通过shell分析viewer端日志文件
  • 深入解析享元模式:通过共享技术高效支持大量细粒度对象
  • 【力扣 简单 C】70. 爬楼梯
  • 【鸿蒙】鸿蒙操作系统发展综述
  • 递归与循环
  • 深入理解Reactor调试模式:Hooks.onOperatorDebug() vs ReactorDebugAgent.init()
  • 软件工程经济与伦理
  • 流水线(Jenkins)打包拉取依赖的时候提示无法拉取,需要登录私仓的解决办法
  • HTML知识复习2
  • HuggingFists: 无代码处理复杂PDF
  • 一个简单的网页设计
  • Vue Router 中,params参数的名称必须与路由配置中的动态路径参数名完全一致
  • Go语言基础之接口
  • CppCon 2018 学习:Sane and Safe C++ Class Types
  • FLAN-T5:规模化指令微调的语言模型
  • NumPy 函数库在数学建模中的基本使用方法
  • 电脑休眠控制工具,灵活设置防休眠
  • 通过 Windows 共享文件夹 + 手机访问(SMB协议)如何实现
  • Python(28)Python循环语句指南:从语法糖到CPython字节码的底层探秘
  • Everything 1.5.0.1393a高效实用的系统文件搜索工具(2025年7月4日更新)
  • 构建未来交互体验:AG-UI 如何赋能智能体与前端通信?
  • [论文阅读] 软件工程 | 可持续性标志在问答平台中的应用
  • AI语音训练——GPT-SoVITS(GSV)
  • Vue 笔记:动态绑定内联样式 :style 的关键语法注意事项
  • Spring Boot 框架创建一个简单的后端接口,并介绍如何使用 Apifox 连接该接口
  • Spring中实现依赖注入(DI)的三种方式
  • Spring Bean 生命周期 SmartLifecycle接口介绍和使用场景 和 Lifecycle对比
  • 【Linux】02_CentOS 7 开机运行级别详解:从基础概念到实战配置
  • 浅谈 Vue2 的 Mixin 混入和 Vue3 的 Hooks(组合式 API)