`
wangdeshui
  • 浏览: 256885 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

C#拾遗系列(1):委托

阅读更多

一、委托概述

委托具有以下特点:

  • 委托类似于 C++ 函数指针,但它们是类型安全的。

  • 委托允许将方法作为参数进行传递。

  • 委托可用于定义回调方法。

  • 委托可以链接在一起;例如,可以对一个事件调用多个方法。

  • 方法不必与委托签名完全匹配。(委托中的协变和逆变)

  • C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数

二、委托申明和使用示例

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

//Description: 委托三种声明方式.net1.0到.net3.0

 

namespace NetTest

    public class TestDelegateNet1To3

    {

        #region 不带返回值的委托

        delegate void TestDelegate(string s);

        public void TestAllDelegate()

        {

            //.net 1.0

            TestDelegate en = new TestDelegate(M);

            en("jack");

            TestDelegate china = China;

            china("wangdeshui");

 

            //.net 2.0

            TestDelegate delegateNet2 = delegate(string s) { Console.Out.WriteLine(s + ":这是一个2.0的方式"); };

            delegateNet2("2.0 delegate declare");

 

            //.net 3.0

            TestDelegate delegateNet3 = (string s) => { Console.Out.WriteLine(s + ":这是3.0的方式"); };

            delegateNet3("3.0 delegate declare");

 

            TestReturn(); 

 

            Func<int, bool> d = (n) => { return n > 10 ? true : false; };

            Console.Out.WriteLine("func<int, bool>:" + d(20));

 

 

        }

 

        void M(string s)

        {

            Console.Out.WriteLine(s + ":Good Morning");

        }

 

        void China(string s)

        {

            Console.Out.WriteLine(s + ":早上好");

        }

        #endregion

 

 

        #region 带返回值的委托测试

 

        delegate bool TestDelegateReturn(int i);

        void TestReturn()

        {

            TestDelegateReturn Net10 = new TestDelegateReturn(IsBig);

            bool i = Net10(11);

            Console.Out.WriteLine("Net10:" + i);

 

            TestDelegateReturn Net20 = delegate(int j)

            {

                return (j > 10 ? true : false);

 

            };

 

            bool test20 = Net20(5);

            Console.Out.WriteLine("Net20:" + test20);

 

            TestDelegateReturn Net30 = (int k) => { return (k > 10 ? true : false); };

            bool test30 = Net30(50);

            Console.Out.WriteLine("Net30:" + test30);

 

        }

 

        bool IsBig(int i)

        {

            return i > 10 ? true : false;

 

        }

 

        #endregion

    }

}

 

三、多播委托

调用委托时,它可以调用多个方法。这称为多路广播。若要向委托的方法列表(调用列表)中添加额外的方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。

注意:

作为委托参数传递的方法必须与委托声明具有相同的签名。
委托实例可以封装静态或实例方法。
尽管委托可以使用 out 参数,但建议您不要将其用于多路广播事件委托,因为您无法知道哪个委托将被调用。

多播委托传递值类型时,对参数的修改不会传到下一个
多播委托传递引用类型时,对引用参数的修改会传到下一个

示例:

public class TestMultiCastDelegate

    {

        public delegate void Del(string message);

        delegate void DelRef(Person p);

        void MethodA(string s)

        {

            Console.Out.WriteLine("Method A:"+s);

        }

 

        void MethodB(string s)

        {

            s = "good";

            Console.Out.WriteLine("Method B:" + s);

        }

 

        void MethodC(string s)

        {

            Console.Out.WriteLine("Method C:" + s);

        }

 

        /*

        多播委托传递值类型时,对参数的修改不会传到下一个

        多播委托传递引用类型时,对引用参数的修改会传到下一个

        *

        * */

 

        public void Test()

        {

            //多播委托

            Del d1 = MethodA;

            Del d2 = MethodB;

            Del d3=MethodC;

            Del AllDelegateMethod = d1 + d2;

            AllDelegateMethod += d3;

            AllDelegateMethod("Jack");

            /*

            output:

            ConsoleA: Jack

            ConsoleB: Jack

            ConsoleC:Jack           

            */

            Console.Out.WriteLine("---------------------");

            AllDelegateMethod -= d3;

            AllDelegateMethod("wangds");

 

 

            //测试引用类型

            DelRef dref1 = MethodRefA;

            DelRef dref2 = MethodRefB;

            DelRef Alldref = dref1 + dref2;

            Person p = new Person { Address = "USA", Name = "America" };

            Alldref(p);

        }

 

 

        //内嵌类

 

        class Person

        {

            public string Name { get; set; }

            public string Address { getset; }

 

        }

 

        void MethodRefA(Person p)

        {

            Console.Out.WriteLine(p.Name + "," + p.Address);

            Console.Out.WriteLine("----------MethodRefA---------");

            p.Name = "Jack";

            p.Address = "China";

 

            Console.Out.WriteLine(p.Name + "," + p.Address);

            Console.Out.WriteLine("----------MethodRefA---------");

        }

 

        void MethodRefB(Person p)

        {

            Console.Out.WriteLine("--------MethodRefB----------");

            Console.Out.WriteLine(p.Name + "," + p.Address);

            Console.Out.WriteLine("--------MethodRefB----------");

        }

    }

四、委托中的协变和逆变

委托中的协变: 就是允许方法的返回类型是委托的返回类型的子类

委托中的逆变,方法的参数是委托的参数的基类

示例:

#region 委托中的协变: 就是允许方法的返回类型是委托的返回类型的子类

    class Mammals

    {

    }

 

    class Dogs : Mammals

    {

    }

 

    class XieBianDelegate

    {

        // Define the delegate.

        public delegate Mammals HandlerMethod();

 

        public Mammals FirstHandler()

        {

            return null;

        }

 

        public Dogs SecondHandler()

        {

            return null;

        }

 

        void Test()

        {

            HandlerMethod handler1 = FirstHandler;

 

            // Covariance allows this delegate.

            HandlerMethod handler2 = SecondHandler;

        }

    }

    #endregion

 

 

    #region   委托中的逆变,方法的参数是委托的参数的基类

    class NiBianDelegate

    {

        public delegate Dogs HandlerNibianMethod(Dogs dogs);

        public Dogs FirstHandlerNibian(Mammals mammals)

        {

            return null;

        }

 

        void Test()

        {

            Dogs dogs = new Dogs();

            HandlerNibianMethod handNibian1 = FirstHandlerNibian;

 

        }

 

    }

    #endregion

五、委托综合示例(来自MSDN)

下面的示例阐释声明、实例化和使用委托。BookDB 类封装一个书店数据库,它维护一个书籍数据库。它公开 ProcessPaperbackBooks 方法,该方法在数据库中查找所有平装书,并对每本平装书调用一个委托。使用的 delegate 类型名为 ProcessBookDelegate。Test 类使用该类打印平装书的书名和平均价格。

委托的使用促进了书店数据库和客户代码之间功能的良好分隔。客户代码不知道书籍的存储方式和书店代码查找平装书的方式。书店代码也不知道找到平装书后将对平装书执行什么处理。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace Bookstore

{

    using System.Collections;

 

    // Describes a book in the book list:

    public struct Book

    {

        public string Title;        // Title of the book.

        public string Author;       // Author of the book.

        public decimal Price;       // Price of the book.

        public bool Paperback;      // Is it paperback?

 

        public Book(string title, string author, decimal price, bool paperBack)

        {

            Title = title;

            Author = author;

            Price = price;

            Paperback = paperBack;

        }

    }

 

    // Declare a delegate type for processing a book:

    public delegate void ProcessBookDelegate(Book book);

 

    // Maintains a book database.

    public class BookDB

    {

        // List of all books in the database:

        ArrayList list = new ArrayList();

 

        // Add a book to the database:

        public void AddBook(string title, string author, decimal price, bool paperBack)

        {

            list.Add(new Book(title, author, price, paperBack));

        }

 

        // Call a passed-in delegate on each paperback book to process it:

        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)

        {

            foreach (Book b in list)

            {

                if (b.Paperback)

                    // Calling the delegate:

                    processBook(b);

            }

        }

    }

}

 

 

 

 

// Using the Bookstore classes:

namespace BookTestClient

{

    using Bookstore;

 

    // Class to total and average prices of books:

    class PriceTotaller

    {

        int countBooks = 0;

        decimal priceBooks = 0.0m;

 

        internal void AddBookToTotal(Book book)

        {

            countBooks += 1;

            priceBooks += book.Price;

        }

 

        internal decimal AveragePrice()

        {

            return priceBooks / countBooks;

        }

    }

 

    // Class to test the book database:

  public  class TestBookDB

    {

        // Print the title of the book.

        void PrintTitle(Book b)

        {

            System.Console.WriteLine("   {0}", b.Title);

        }

 

        // Execution starts here.

        public void Test()

        {

            BookDB bookDB = new BookDB();

 

            // Initialize the database with some books:

            AddBooks(bookDB);

 

            // Print all the titles of paperbacks:

            System.Console.WriteLine("Paperback Book Titles:");

 

            // Create a new delegate object associated with the static

            // method Test.PrintTitle:

            bookDB.ProcessPaperbackBooks(PrintTitle);

 

            // Get the average price of a paperback by using

            // a PriceTotaller object:

            PriceTotaller totaller = new PriceTotaller();

 

            // Create a new delegate object associated with the nonstatic

            // method AddBookToTotal on the object totaller:

            bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

 

            System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",

                    totaller.AveragePrice());

        }

 

        // Initialize the book database with some test books:

        static void AddBooks(BookDB bookDB)

        {

            bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);

            bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true);

            bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false);

            bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true);

        }

    }

}

 

 

分享到:
评论

相关推荐

    C#委托详解:匿名委托,委托的应用(含源代码)

    在C#编程语言中,委托扮演着至关重要的角色,它是一种类型安全的函数指针,允许我们传递方法作为参数或存储方法以供后续调用。本文将深入探讨C#中的委托,特别是匿名委托以及它们在实际应用中的用法,并提供相应的源...

    C#委托 C#委托 C#委托

    在C#编程语言中,委托(Delegate)是一种强大的特性,它允许我们把方法作为参数传递,或者存储在变量中,从而实现回调函数和事件处理。本文将深入探讨C#委托的概念、用途、类型以及如何使用`DynamicInvoke`方法。 #...

    Modern C#(11):深入“委托和事件” (Level 300)

    Modern C#(11):深入“委托和事件” (Level 300) 讲 师:俞晖 MSDN 特邀讲师 课程简介:本次课程是系列课程《现代软件开发——使用.NET与C#》的第十一讲(即重开第一讲), 这次系列讲座的目的是为希望从...

    第25讲:委托与事件实例浅析(C#视频教程 + C#源代码).zip

    [第25讲:委托与事件实例浅析(C#视频教程 + C#源代码).zip] 根据【田洪川 天轰穿 C#视频教程】的【第25讲:委托与事件实例浅析】实现,VS2010编译运行正常。 源代码与视频教程中略有不同! 本人不是天轰穿,在此对...

    《.NET-C#面试手册》

    .NET/C#⾯试题汇总系列:集合、异常、泛型、LINQ、委托、EF! .NET/C#⾯试题汇总系列:多线程 .NET/C#⾯试题汇总系列:ASP.NET MVC .NET/C# ⾯试题汇总系列:ASP.NET Core .NET/C#⾯试题汇总系列:ADO.NET、XML、...

    C#入门相关代码:delegateTest

    6. **事件处理**:委托在C#事件处理模型中扮演重要角色。事件是对象之间的通信机制,而事件处理程序通常通过委托实现。事件源对象发布事件,其他对象订阅事件并提供处理程序。 7. **委托的内存管理**:由于委托是...

    C#射击类游戏:龙之战(源码)

    开发语言:C# 参考网络上流传的《勇者斗恶龙》游戏源码制作的一个射击类游戏,借用了《勇者斗恶龙》的游戏界面及部分源码。 整个游戏框架已基本完成,源码中采用了一些设计模式,有精美的游戏画面和详尽的代码注释,...

    对C#委托及事件委托的理解

    1. **委托的定义**: 委托在C#中是一种类型,它类似于函数指针,但比函数指针更安全,因为它是类型安全的。声明委托时,我们需要使用`delegate`关键字,定义一个方法签名,表示该委托可以指向的方法应具有的参数...

    C#面向对象程序设计委托PPT与实例

    5. **事件处理**:委托在事件驱动编程中的应用,如何声明、触发和订阅事件。 接下来,我们来看看四个实现委托的小程序可能涉及的主题: 1. **基本委托示例**:一个简单的程序,演示如何声明委托、实例化并调用委托...

    编程学C#(1):VS2010 C# Access数据库管理程序

    编程学C#(1):VS2010 C# Access数据库管理程序,1. 基于VS2010 C# 的的Access数据库管理设计; 2. 数据集的创建; 3. .NET组件,dataGridview 控件的使用; 4. 数据库的插入、删除、查询操作设计。

    c#多线程利用委托更新控件内容

    C# 多线程利用委托更新控件内容 在 C# 编程中,多线程编程是常见的场景之一,特别是在需要实时更新控件内容的情况下。为了解决多线程之间的数据更新问题,本文将介绍如何使用委托(delegate)来更新控件的内容。 ...

    C# 委托和事件 (详细讲解)

    在C#编程语言中,委托和事件是两个关键的概念,它们是实现面向对象设计模式,尤其是事件驱动编程的核心。下面将详细阐述这两个概念及其在实际编程中的应用。 **委托** 委托在C#中相当于一种类型,它封装了指向方法...

    第26讲:深入委托(C#视频教程 + C#源代码).zip

    [第26讲:深入委托(C#视频教程 + C#源代码).zip] 根据【田洪川 天轰穿 C#视频教程】的【第26讲:深入委托】实现,VS2010编译运行正常。 源代码与视频教程中略有不同! 本人不是天轰穿,在此对田洪川老师表示感谢!

    c#中的委托及其调用

    - **面向对象**:委托是面向对象的一部分,这意味着它们可以绑定到对象实例,并可以访问该对象的状态。 #### 如何声明和使用委托 ##### 1. 声明委托 使用`delegate`关键字声明一个新的委托类型。委托的声明通常...

    金旭亮《C#面向对象程序设计》教案_6:委托与事件

    金旭亮《C#面向对象程序设计》教案_6:委托与事件。此教案重点介绍.NET平台上的重要技术——委托,以及对建立于委托基础之上的.NET事件响应机制的深入剖析。包括两个29页的PDF文档及数个VS2010示例。前几讲的教案请...

    Winform(C#)委托+进度条赋值+线程安全(全新)

    1. **委托(Delegate)**: 委托在C#中是一种类型,它代表一个方法的引用。它可以像处理其他类型一样被传递给方法,也可以作为方法的返回值。在Winform中,委托经常用于事件处理,使代码能够异步执行。例如,当启动一...

    C#的Demo项目:RabbitMQ封装和使用

    1. **Direct Exchange**(直连交换机):最简单的交换机类型,按照路由键(Routing Key)将消息精确地投递给对应的队列。在C#项目中,可以创建一个DirectExchange类,设置路由键和队列绑定,实现一对一的消息传递。 ...

    C#多线程委托

    3. 事件和事件处理程序:委托在事件处理中也扮演重要角色,通过+=运算符订阅事件,使用-=取消订阅。 三、UI更新与委托 在多线程环境中,由于UI线程和后台线程之间的同步问题,直接在非UI线程上修改UI元素可能会导致...

    C#跨窗体更新-委托实例

    在C#编程中,"跨窗体更新-委托实例"是一个关键的概念,它涉及到多窗口应用程序的通信和数据同步。本文将深入探讨这个主题,并通过一个具体的实例来讲解如何使用委托来实现窗体间的交互。 首先,理解"跨窗体更新...

Global site tag (gtag.js) - Google Analytics