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<intbool> 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 { getset; }

            public string Address { get;  set; }

 

        }

 

        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.

本文转自敏捷的水博客园博客,原文链接http://www.cnblogs.com/cnblogsfans/archive/2008/06/11/1217381.html如需转载请自行联系原作者


王德水

相关文章
|
6月前
|
C#
C#拾遗补漏之goto跳转语句
在我们日常工作中常用的C#跳转语句有break、continue、return,但是还有一个C#跳转语句很多同学可能都比较的陌生就是goto,今天大姚带大家一起来认识一下goto语句及其它的优缺点。
|
2月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
109 7
|
3月前
|
编译器 C#
C#中内置的泛型委托Func与Action
C#中内置的泛型委托Func与Action
62 4
|
3月前
|
C#
C#中的委托(一)
C#中的委托(一)
37 1
|
3月前
|
C# C++
C#语言进阶(一)—委托
C#语言进阶(一)—委托
45 0
|
5月前
|
XML 开发框架 人工智能
C#/.NET/.NET Core拾遗补漏合集(24年5月更新)
C#/.NET/.NET Core拾遗补漏合集(24年5月更新)
|
6月前
|
存储 安全 C#
C# - 委托与事件
这篇文档介绍了C#中的委托和事件。委托是存储方法引用的类型,支持回调、事件处理,具有引用方法、类型安全、多播性等特性,并在异步编程中发挥作用。事件是委托的封装,提供保护和订阅机制,防止外部直接访问。当需要在类内部控制方法调用,防止外部误触发时,可使用事件。
|
5月前
|
C#
C#||委托和事件的实例
C#||委托和事件的实例
|
6月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
在这个快速发展的技术世界中,时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节,以帮助大家更全面地了解这些技术栈的特性和发展方向。