委托详解

委托

为什么要使用委托:

我们习惯性的把数据当做参数传递给方法,如果给方法传递一个方法呢?但是往往有时候我们要给一个方法传递另一个方法。更麻烦的是,有时候我们并不知道程序在编译时才知道应该传递哪一个方法。但是.NET Framework语法是不允许直接调用方法的,必须把方法的细节封装在一种新类型的对象中,这个新类型就是委托。关键字是delegate。委托是一个特殊的类型对象,其特殊之处在于,我们以前定义的对象包含的是数据,但是委托保护哈韩的只是一个方法或多个方法的地址。

与委托相关的类与关键字(如果不想知道语言如何实现的,就先跳过这一部分,看完具体实现,再来看看C#是如何实现的)

Delegate类:

Delegate 类是委托类型的基类。 然而,只有系统和编译器可以显式地从Delegate 类或 MulticastDelegate 类派生。此外,还不允许从委托类型派生新类型。 Delegate 类不是委托类型,该类用于派生委托类型。

大多数语言实现 delegate 关键字,这些语言的编译器能够从 MulticastDelegate 类进行派生;所以,用户应当使用语言所提供的 delegate 关键字。

公共语言运行时为每个委托类型提供 Invoke 方法(使用与该委托相同的签名)。不必从 C#、Visual Basic 或 Visual C++ 显式调用此方法,因为编译器将自动调用此方法。需要查找委托类型的签名时 Invoke 方法在反射 上很有用。

托管语言使用 Combine 和 Remove 方法实现委托操作。示例包括 Visual Basic 中的 AddHandler 和 RemoveHandler 语句以及 C# 中委托类型上的 += 和 -= 运算符。

如何使用委托

下面这个例子有三种委托的使用方法;

首先要定义一个委托:没有public delegate string GetString();

第一种直接把系统方法绑定到委托上:

GetString g = new GetString(i.ToString);

g();

第二种:把系统方法ToString()委托给GetString

GetString g = i.ToString;

g();

第三种:通过结构体进行委托。

g = new GetString(c.GetCurrency);

g();

class Program
    {
        //定义一个没有参数,返回值为string 类型的委托。
        //define delegate no parameter and return string
        public delegate string GetString();
        static void Main(string[] args)
        {
            int i = 40;
            //直接把系统方法ToString()委托给GetString
           // GetString g = new GetString(i.ToString);
            //使用另一种方法把系统方法ToString()委托给GetString
            GetString g = i.ToString;
            Console.WriteLine( "string is "+ g() );
            //通过结构体使用委托
            Currency c = new Currency(34, 50);
            g = c.ToString;
            Console.WriteLine("string is " + g());
            g = new GetString(c.GetCurrency);
            Console.WriteLine("string is " + g());
            Console.ReadKey();
        }
    }
    struct Currency
    {
        public uint Dollars;
        public ushort Cents;
        public Currency(uint Dollars,ushort Cents)
        {
            this.Dollars = Dollars;
            this.Cents = Cents;
        }
        public override string ToString()
        {
            return string.Format("${0}.{ 1,2:00}",this.Dollars,this.Cents);
        }
        public string GetCurrency()
        {
            return "Dollar";
        }
        public static explicit operator Currency(float value)
        {
            //checked是什么意思。
            checked
            {
                uint dollars=(uint )value ;
                ushort cents = (ushort)((value - dollars) * 100);
                return new Currency(dollars,cents);
            }
        }
        //对float类型进行重载。
        public static implicit operator float (Currency value)
        {
            return value.Dollars+(value.Cents/100.0f);
        }
        //对Currency类型进行重载
        public static implicit operator Currency (uint value)
        {
            return new Currency(value, 0);
        }
        //对uint类型进行重载。。
        public static implicit operator uint(Currency value)
        {
            return value.Dollars;
        }
}

如果你是一个合格的程序员,请认真思考程序中一下三个问题:

1、  checked关键字是干嘛用的?

2、  还有结构体最后三个函数是什么意思?(点击获得答案。

3、  string.Format("${0}.{ 1,2:00}",this.Dollars,this.Cents);其中${0}.{1,2:00}如何实现的?

第二个实例:

下面这个例子,仅仅使用委托来调用两个不同的操作。它说明了如何把委托传递给方法,如何使用委托数组。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestDelegateSimple
{
    delegate double DoubleOp(double value);
    class Program
    {
        static void Main(string[] args)
        {
            DoubleOp[] options = { MathOptions.MultiplyTwo, MathOptions.Square};
            for (int i = 0; i < options.Length; i++)
            {
                Console.WriteLine("using option[{0}]",i);
                ProcessAndDisplayNumber(options[i], 2.0);
                ProcessAndDisplayNumber(options[i], 7.94);
                ProcessAndDisplayNumber(options[i], 1.414);
            }
            Console.ReadKey();
        }
        private static void ProcessAndDisplayNumber(DoubleOp d,double value)
        {
            double d1 = d(value);
            Console.WriteLine("value is {0},result of option is {1}",value,d1);
        }
    }
    class MathOptions
    {
        public static double MultiplyTwo(double value)
        {
            return value * 2;
        }
        public static double Square(double value)
        {
            return value * value;
        }
    }

}

多播委托:

前面使用的都是包含一个方法的调用,如果想调用多个方法,就需要多次显示调用这个委托,也可以包含多个方法,这种成为委托多播。

把上一个例子改为多播的情况:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DuoBoDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
           Action <double >options = MathOptions.MultiplyTwo;
           options+=MathOptions.Square;

                ProcessAndDisplayNumber(options, 2.0);
                ProcessAndDisplayNumber(options, 7.94);
                ProcessAndDisplayNumber(options, 1.414);
            Console.ReadKey();
        }
        private static void ProcessAndDisplayNumber(Action<double> d, double value)
        {
            Console.WriteLine();
            Console.WriteLine("value is {0},result of option is", value);
            d(value);
        }
    }
    class MathOptions
    {
        public static void MultiplyTwo(double value)
        {
            double result = value * 2;
            Console.WriteLine("MutiplyTwo by 2:{0} give {1}",value,result);
        }
        public static void Square(double value)
        {
            double result = value * value;
            Console.WriteLine("MutiplyTwo by 2:{0} give {1}", value, result);
        }
    }
}

第三个实例:

委托泛型:Action<T>与Func<T>委托。

除了上面的定义委托的方法还可以使用这两种方法定义委托。

Action<T>:表示引用一个void返回类型的方法。Action<inT1>表示一个参数的没有返回的委托。Action<in T1,in T2>表示两个参数的没有返回的委托。

Func<T>:表示引用一个有返回类型的方法。Func<inT1,out TResult>,表示一个参数的有返回值的参数。

上一个例子只是说明了委托的多种实现,并没有很好的说明,没有委托不能实现这些方法。他有一个类BubbleSorter,该类实现了一个排序算法,没有委托很难编写这个类。这个类可以排序任何一种类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BobbleSorter
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee[] employee = {
                                  new Employee("jack",1220),
                                  new Employee("jason",2),
                                  new Employee("jonee",2999),
                                  new Employee("alvin",100),
                                  };
            BubbleSorter.Sort(employee, Employee.CompareSalary);
            foreach (var item in employee)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }
    }
    //排序类
    #region Sorter Class
    class BubbleSorter
    {
        public BubbleSorter()
        {

        }
        public static void Sort<T>(IList<T> sortArray,Func<T,T,bool> comparsion)
        {
            bool swapped = true;
            do
            {
                swapped = false;
                for (int i = 0; i < sortArray.Count-1; i++)
                {
                    if (comparsion(sortArray[i+1],sortArray[i]))
                    {
                        T temp = sortArray[i];
                        sortArray[i] = sortArray[i + 1];
                        sortArray[i + 1] = temp;
                        swapped = true;
                    }
                }
            } while (swapped);
        }
    }
    #endregion
    //员工类
    #region Employee Class
    class Employee
    {
        private string name;
        private decimal salary;

        public decimal Salary
        {
            get { return salary; }
            set { salary = value; }
        }
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Employee()
        { 

        }
        public Employee(string name,decimal salary)
        {
            this.name = name;
            this.salary = salary;
        }
        public override string ToString()
        {
            return string.Format("{0},{1:C}",this.name,this.salary);
        }
        public static bool CompareSalary(Employee e1, Employee e2)
        {
            return e1.Salary < e2.Salary;
        }
    }
    #endregion

}

思考:为什么类中方法public static void Sort<T>(IList<T>sortArray,Func<T,T,bool> comparsion)

参数为什么是Ilist泛型集合,但是传入的一个数组?

匿名方法:

匿名方法就是使一段代码作为委托的参数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NiMingDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            string mid = ",middle part,";
            Func<string, string> anonDel = delegate(string para)
            {
                para += mid;
                para += "and this is add the string";
                return para;
            };
            Console.WriteLine(anonDel("Start of string"));
            Console.ReadKey();
        }
    }
}

对于上面的思考题有不会的,可以回复我。我给你解答》》》

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 08:23:42

委托详解的相关文章

.Net委托详解

搬运自http://wurang.me/2014/04/22/delegate.html [什么是委托] 委托是对函数的引用,它是一个引用类型,类似c/cpp中的函数指针.但它是类型安全的. 委托是一个类,定义了方法的类型,可以将方法当做另一个方法的参数传递. 委托就是一个安全的函数指针,用来执行函数方法的东西. [如何使用委托] 在.Net框架下,委托的使用方法经历了多次改变. 最初委托的使用方法如下: public delegate string MyDelegate(string name

c# 委托详解

1.委托声明 2.委托入门实例 namespace ConsoleApplication1 { public delegate void methodDelegate(string str); class Program { static void Main(string[] args) { Student student = new Student(); Teacher teacher = new Teacher("王老师"); methodDelegate methodDelega

基础拾忆------委托详解

目录: 基础拾忆------委托详解 基础拾忆------接口详解 基础拾忆------泛型详解 前言: C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变.委托(Delegate)特别用于实现事件和回调方法.所有的委托都派生自 System.Delegate 类.把一个方法当作参数传递,让其它方法进行调用执行. 好比:今天中午不想出去,委托小明帮我带份饭,我要买饭,但是小明帮我买的. 1.委托的声明 委托声

事件委托详解

基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数. 举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发

JavaScript 事件委托详解

基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数. 举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发

JS中的事件委托详解(未完)

什么是JS事件委托呢? 首先,我们要明确什么是事件:所谓的事件就是像:onclick,onmouseover,onmouseover.......这些事件,那委托呢?就是指原来发生在这些事件上的元素,加到其它的元素身上来完成. JS事件委托的原理:就是利用冒泡的原理,把事件加到父级或是父级的父级身上,来触发执行操作. 使用事件委托的优势:1)提高性能: 2)新添加的元素也会有之前加的事件: 下面我们用例子来说明一下:点击改变li的背景颜色 HTML部分: 1 <ul id="ul1&quo

C#事件与委托详解【精华 多看看】

Delegate delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类.与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与它的签名相匹配的方法的引用".它所实现的功能与C/C++中的函数指针十分相似.它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m.但与函数指针相比,delegate有许多函数委托和事件在 .Net Framework中的应用非常广泛指针不具备的优点.首先,函数指针只能指

[C#基础知识]委托详解

1. 委托是什么? 个人认为,可以从以下2点来理解:  (1) 从数据结构来讲,委托是和类一样是一种用户自定义类型. (2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象. 既然委托是一种类型,那么它存储的是什么数据? 我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址.调用委托的时候,委托包含的所有方法将被执行. 2. 委托类型的定义 委托是类型,就好像类是类型一样.与类一样,委托类型必须在被用来创建变量以及类型对象之前声明. delegate void

C#3.0新特性&mdash;&mdash;委托详解

前言   委托的定义 委托的本质:函数指针.让方法作为变量一样传递. 定义:委托是一种类型安全的函数回调机制, 它不仅能够调用实例方法,也能调用静态方法,并且具备按顺序执行多个方法的能力. 也就是说,委托可以在程序运行时调用不同方法函数,只要这个方法签名和委托签名保持一致.与函数指针不同的是,委托是类型安全的.所谓类型安全,是指在编译时编译器会检测委托对象的签名是否委托声明一致. using System; using System.Collections.Generic; using Syst