C#委托

委托的定义与方法的定义类似,只是返回值类型的前面多了个delegate。如:public delegate void PrientDelegate(string content),其实委托就是一个能够将方法封装成一个引用类型,能和普通对象一样传递。

一、委托的声明有几点要注意的,

  1、和类一样,委托的声明可以再类的外部声明,委托也可以再类的内部声明。

  2、委托的声明虽然形式上与方法很像,但是它没有方法主体,而是直接以分号结尾。

  3、修饰符可以是new、public、protected、internal、private。

  4、delegate关键字后是本委托类型可以匹配的方法签名,尤其需要注意的是,它还包括方法的返回类型,但并非与方法名完全匹配。

二、给委托绑定方法时,要符合以下两点要求。

  1、方法的签名要与委托一样,方法参数的个数和类型。

  2、方法的返回值类型要与委托一样。

调用委托就相当于调用委托所绑定的方法, 一个委托可以绑定多个方法。委托是引用类型,因此它就可以到处传递,没有它,C#能够将方法到处传递吗?

先附上一个基础的例子

复制代码
    public delegate void Print(string str);  //声明一个委托

    class Program
    {
        public static void PrintString(string str)
        {
            Console.WriteLine(str);
        }

        static void Main(string[] args)
        {
            //创建一个委托对象,并将方法PrintString赋给该委托
            Print p = new Print(Program.PrintString);
            //Print p = Program.PrintString;    //直接用=号也可以让委托绑定方法。

            p("调用委托实际等于调用了委托所绑定的方法!");  //输出调用委托实际等于调用了委托所绑定的方法!
            Console.ReadKey();
        }
    }
复制代码

三、委托的组合(多个委托之间的关系)

  "+"可以将两个委托组合起来,"-"可以从一个委托组合中删除其中一个成员。

复制代码
    public delegate void Print();

    class Program
    {
        public static void PrintString1()
        {
            Console.WriteLine("我是第一个方法");
        }

        public static void PrintString2()
        {
            Console.WriteLine("我是第二个方法");
        }

        static void Main(string[] args)
        {
            //创建一个委托对象并绑定方法
            Print p1 = Program.PrintString1;    //委托p1绑定方法1
            Print p2 = Program.PrintString2;    //委托p2绑定方法2

            Print p3 = p1 + p2; //将p1委托和p2委托组合成一个新委托p3
            p3();       //调用委托p3,相当于调用p3所有已经绑定的方法,此时是方法1与方法2,此时输出 我是第一个方法 "换行" 我是第二个方法
            Print p4 = p3 - p1;    //创建一个新的委托对象,其绑定的方法为p3委托组合去除委托p1,实际就只剩下p2
            p4();       //调用委托p4,相当于调用所有p4绑定的方法 输出 我是第二个方法

            Console.ReadKey();
        }
    }
复制代码

四、委托的添加方法与删除方法(一个委托的事情)

  通过"+="符可以像已有委托新添加绑定一个方法,通过"-="可以从委托中删除一个已绑定的方法。

复制代码
    public delegate void Print();

    class Program
    {
        public static void PrintString1()
        {
            Console.WriteLine("我是第一个方法");
        }

        public static void PrintString2()
        {
            Console.WriteLine("我是第二个方法");
        }

        static void Main(string[] args)
        {
            Print p = PrintString1; //声明一个委托并绑定第一个方法
            p();    //调用委托p  输出 我是第一个方法
            p += PrintString2;  //再为p多绑定一个方法
            p();    //调用委托p 输出我是第一个方法 "换行" 我是第二个方法,看到现在p委托一经是绑定两个方法的了
            p -= PrintString1;  //从委托p中删除一个已经绑定的方法p1;
            p();    //调用委托p 输出 我是第二个方法  看到p现在已经是只绑定第二个方法了

            Console.ReadKey();
        }
    }
复制代码

 五、委托在回调中的应用

复制代码
    public delegate void PrintCompleteCallback(string message);

    class Program
    {
        public static void PrintMessage(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            PrintCompleteCallback CompleteCallback = Program.PrintMessage;  //创建一个委托,并绑定PrintMessage方法
            Printer printer = new Printer("我是一个打印机");
            printer.Print(CompleteCallback);  //调用p对象的Print方法,要求传入一个委托作为参数,相当于传入一个方法作为参数

            Console.ReadKey();
        }
    }

    public class Printer
    {
        private string _name;
        public Printer(string name)
        {
            _name = name;
        }

        public void Print(PrintCompleteCallback callback)  //委托对象作为方法参数
        {
            callback(_name + "打印完毕");   //调用委托,相当于调用callback委托所绑定的对象
        }
    }
复制代码

 六、匿名方法

  匿名方法最大的优势在于其减少了系统开销,方法仅在委托使用时才定义。直接给委托传递一段代码比先创建一个方法再绑定到委托要简单。

  匿名方法的使用规则:

  1、匿名方法中不能使用跳转语句跳至此匿名方法的外部,反之亦然;匿名方法外部的跳转语句也不能跳到此匿名方法的内部。

  2、在匿名方法内部不能访问不安全的代码。另外,也不能访问在匿名方法外部定义的ref与out参数。但可以使用在匿名方法外部定义的其它变量。

复制代码
    public delegate void Print();   //定义一个委托

    public delegate int GetLength(string str);  //定义一个带参数的委托
    class Program
    {
        static void Main(string[] args)
        {
            Print p = delegate      //不带参数的匿名方法
            {
                Console.WriteLine("你在他乡还好吗?");
            };
            p();

            GetLength g = delegate(string str)  //带参数的匿名方法,注意方法的参数要与委托一致
            {
                return str.Length;
            };

            int length = g("你还好吗?");    //调用委托,注意要传入参数
            Console.WriteLine(length);

            Console.ReadKey();
        }
    }
复制代码

七、Lambda表达式

  Lambda表达式和匿名方法基本相同,只是语法不同而已,可以说,Lambda表达式就是匿名方法。必须要记住,Lambda就是一个匿名方法,是给委托赋值用的,也就是说,使用Lambda的场景只有给委托赋值。

  Lambda表达式的语法更加简洁:

    (param)=>expr  //其中param是一个输出参数列表,说白了就是给委托的参数,expr是一个表达式或一系列语句,说白了就是输出或执行的操作

  Lambda表达式具有以下特性:

  1、在一个具有唯一的显式类型参数的Lambda表达式中,圆括号可以从参数列表中删除。例如:param=>expr

  2、当输入参数不唯一时,括号不能省略。

  3、输入参数列表中的各参数可以显式指定类型,也可以省略掉参数类型,具体类型通过类型推断机制判断。

  4、expr可以只包含一个计算表达式,也可以包含一系列语句,只是如果是一系列语句必须包括在大括号内。

 一个委托参数的Lambda表达式

复制代码
    public delegate string Print(string content);   //定义一个委托,该委托接受一个字符串输入,用于Lambda的左边

    class Program
    {
        static void Main(string[] args)
        {
            Print p = (str) => str += "-输出参数";  //(str) 输入参数,也就是委托参数中的content,箭头后的是输出,最简单的理解就是,箭头左边是输入,箭头左边是输出,当然语句就不同了。
            string outstr = p("输入参数");
            Console.WriteLine(outstr);  //输出 输入参数-输出参数

            Console.ReadKey();
        }
    }
复制代码

 两个委托参数的Lambda表达式的调用

复制代码
    public delegate string Print(string content1,string content2);   //定义一个委托

    class Program
    {
        static void Main(string[] args)
        {
            Print p = (str1,str2) => str1 += "左边-右边" + str2;  //多个输入参数,括号不能省略
            string outstr = p("张飞","关羽");   //输出    张飞左边-右边关羽
            Console.WriteLine(outstr);  //输出 输入参数-输出参数

            Console.ReadKey();
        }
    }
复制代码

带语句的Lambda表达式

复制代码
    public delegate void Print(string content);   //定义一个委托

    class Program
    {
        static void Main(string[] args)
        {
            Print p = str =>  //带语句的Lambda表达式,由于只有一个参数,所以小括号可以省略
            {
                Console.WriteLine(str);
            };
            p("你好");    //你好

            Console.ReadKey();
        }
    }
复制代码

 八、委托中的协变与逆变

  协变:委托方法的返回值类型直接或间接地继承自委托签名的返回值类型,称为协变。

  逆变:委托签名中的参数类型继承自委托方法的参数类型,称为逆变。

  注意:协变强调的是返回类型,逆变强调的则是方法参数。

   协变Demo:

复制代码
delegate People getSon(string name);

    class Program
    {
        static void Main(string[] args)
        {
            getSon g = sons;
            People p = g("张飞");     //注意虽然委托方法返回的是Son,但是委托本身返回的是父类People
            Console.WriteLine(p.Name);  //输出    张飞
            Console.ReadKey();
        }

        public static Son sons(string name)     //委托方法的返回值类型继承自委托签名的返回值类型  逆变
        {
            Son m = new Son();
            m.Name = name;
            return m;
        }

    }

    public class People
    {
        public People()
        {
        }

        public int Id
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }
    }

    public class Son : People
    {
        public int Age 
        {
            get;
            set;
        }
    }
复制代码

  逆变Demo:

复制代码
delegate string getSonName(Son s);

    class Program
    {
        static void Main(string[] args)
        {
            getSonName g = sons;
            Son s = new Son();
            s.Name = "关羽";
            string str = g(s);
            Console.WriteLine(str);     //输出    关羽

            Console.ReadKey();
        }

        public static string sons(People p)     //委托签名的参数类型继承自委托方法的参数类型 此People为委托签名参数Son的父类
        {
            return p.Name;
        }

    }

    public class People
    {
        public People()
        {
        }

        public int Id
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }
    }

    public class Son : People
    {
        public int Age 
        {
            get;
            set;
        }
    }
复制代码
资源下载链接为: https://pan.quark.cn/s/9648a1f24758 Java JDK(Java Development Kit)是Java编程语言的核心组件,为开发和运行Java程序提供了必要的工具和环境。JDK 8是Oracle公司推出的一个重要版本,它引入了许多新特性和改进,极大地提升了开发效率和代码质量,对开发者来说具有极高的实用价值。 本次提供的“jdk-8u251-macosx-x64.dmg”安装包是专为Mac OS X系统设计的64位版本,其中不仅包含了Java运行环境(JRE),还涵盖了丰富的开发工具,方便用户在Mac平台上进行Java程序的开发与运行。 JDK 8的关键更新和特性如下: Lambda表达式:这是JDK 8的一项重大语法创新,允许开发者使用简洁的匿名函数替代复杂的多行回调代码,从而使代码更加简洁、易读且高效。 方法引用与构造器引用:与Lambda表达式配合使用,可以更直观地引用已有的方法或构造器,进一步减少冗余代码,提升代码的可维护性。 Stream API:这是一个用于处理集合的新API,采用声明式处理方式,使集合操作(如过滤、映射和归约等)更加高效且易于理解。 日期和时间API的改进:JDK 8对日期和时间API进行了重构,引入了java.time包,包含LocalDate、LocalTime和LocalDateTime等类,替代了原有的java.util.Date和java.util.Calendar,使日期和时间的处理更加友好和灵活。 Optional类:为解决null对象导致的空指针异常问题,JDK 8引入了Optional类,它是一个容器对象,可以表示一个值存在或不存在,从而有效避免空指针异常。 接口的默认方法和静态方法:接口现在可以定义默认方法(使用default关键字)和静态方法。默认方法允许在不破坏向后
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值