委托 订阅
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。 展开全文
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
信息
外文名
delegate
定    义
方法的类型
作    用
程序具有更好的可扩展性
中文名
委托
解    释
用来执行方法(函数)的一个东西
委托引言
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
收起全文
精华内容
参与话题
问答
  • 委托

    千次阅读 多人点赞 2012-02-18 22:45:36
    委托的概念 委托实际上是类(一个貌似函数一样的类),我们已经使用函数指针很多年了——函数指针也被称为过程类型,但是它们的实现都不是类。它们是单独的函数指针的简单实例。委托是包含这些功能的类,委托类通过...

    委托的概念

    委托实际上是类(一个貌似函数一样的类),我们已经使用函数指针很多年了——函数指针也被称为过程类型,但是它们的实现都不是类。它们是单独的函数指针的简单实例。委托是包含这些功能的类,委托类通过保留的列表来确定某些事物是否已经指派给了委托,这种算法可以理解为:“对于内部列表中的每一个回调函数,都调用函数”。委托除了支持回调函数外,还可以通过该列表来实现多播(委托链)。

    说白了,就是我们把一批具有相同特征的方法,通过建立与具有同样相同特征的委托的一个实例来进行传递,以使其它地方能对这些方法进行调用。即把方法当作参数进行传递(浅显的认识,勿笑)。

     

    初识委托

    示例1:

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Web;

     

     

    namespace MyDelegateTest

    {

         /// <summary>

         /// 说明:一个简单的委托示例

         /// 作者:文野

         /// 联系:stwyhm.cnblogs.com

         /// </summary>

     

         // 新建一个用以输出消息的委托

         public delegate void WriteMessage();

        

         public class WriteToWeb

         {

             // 一个输出消息的静态方法

             public static void StaticWrite()

             {

                  HttpContext.Current.Response.Write("委托调用了一个静态方法。<br />");

             }

     

             // 一个输出消息的类实例方法

             public void Write()

             {

                  HttpContext.Current.Response.Write("委托调用了一个类实例方法。<br />");

             }

         }

    }

    调用:

    protected void Page_Load(object sender, EventArgs e)

        {

             // 新建一个委托,回调函数是一个静态方法

             WriteMessage wm = new WriteMessage(WriteToWeb.StaticWrite);

     

             WriteToWeb w = new WriteToWeb();

             // 新建一个委托并与加到先前建立的委托组成委托链,回调函数是一个类实例方法

             wm += new WriteMessage(w.Write);

     

             // 执行委托链上所有的回调函数

             wm();

        }

     

    上面的示例程序首先建立了一个简单得不能再简单的用以输出的委托,下面的类中有两个与委托签名一致的方法(一个静态方法,一个类实例方法)。下面的调用过程首先建立了一个使用回调静态方法的委托,其后又建立了一个使用类实例方法的委托并与先前的委托组成了一个委托链,最后执行委托链上所有的方法。

    由此可见,委托最简单的理解就是利用与方法签名一致的委托,可以把方法当作参数一样来传递,无论是静态方法还是类实例方法。

     

    委托的秘密


    从上面的类视图中我们看到,对委托的定义最终被编译成一个类,这个类中定义有4种方法:构造器,Invoke,BeginInvoke,EndInvoke。

    所有的委托都继承自MulticastDelegate,而MulticastDelegate又继续至Delegate。这样我们定义的委托自然也就继承了MulticastDelegate的字段、属性和方法。在继承得到的所有成员中,有3个最重要的字段:

    1、_target:指向调用回调函数时应该操作的对象。该字段用于实例方法的回调。

    2、_methodPtr:一个内部的整数值,CLR用它来识别回调的方法。

    3、_prev:指向另一个委托对象。

    当编译器知道我们在构造的是一个委托时,它会分析源代码来确定要引用哪个对象和方法。其中对象引用会被传递给_target(对于静态方法,_target被置为null),一个特殊的标识方法的Int32值会被传递给_methodPtr,_prev在构造器中被置为null,它被用于在委托链中记录下一个委托的引用。

    每个委托对象实际上是对方法及其调用操作的一个包装,MulticastDelegate中定义了两个只读属性,Target和Method,Target(其实就是前面的_target字段)属性返回一个方法回调时操作的对象的引用,Method属性返回一个标识回调方法的System.Reflection.MethodInfo对象。

     

    委托链

    前面介绍过MulticastDelegate中有一个_prev的私有字段,这个字段指向另一个MulticastDelegate对象的引用,这样就实现了委托链(其实与我们在学链表时的实现方式是一致的)。

    当委托链表被调用时,它首先会调用委托中在其前面的委托对象,这里如果被调的回调方法具有返回值,将被丢失,委托链只会返回最后一次调用回调方法的返回值。

     

    委托示例

    这是一个我自认为比较经典的委托示例(给排序算法传递一个动态比较的函数)。

     

    using System;

    using System.Collections.Generic;

    using System.Text;

     

    namespace MyDelegateTest

    {

         /// <summary>

         /// 说明:给排序算法传递一个动态比较函数的委托示例

         /// 作者:文野

         /// 联系:stwyhm.cnblogs.com

         /// </summary>

        

         // 进行排序的委托

         public delegate bool Compare(int left, int right);

     

         public class DelegateSample

         {

             private int[] items;

     

             public int[] Items

             {

                  set { items = value; }

                  get { return items; }

             }

     

             // 比大

             public bool Greater(int left, int right)

             {

                  return left > right;

             }

     

             // 比小

             public bool Less(int left, int right)

             {

                  return !Greater(left, right);

             }

     

             public void Sort(Compare compare)

             {

                  for (int i = 0; i < items.Length-1; i++)

                  {

                       for (int j = i + 1; j < items.Length; j++)

                       {

                           if (compare(items[i], items[j]))

                           {

                                int tmp = items[i];

                                items[i] = items[j];

                                items[j] = tmp;

                           }

                       }

                  }

             }

         }

    }

     

    调用页面

    using System;

    using System.Data;

    using System.Configuration;

    using System.Collections;

    using System.Web;

    using System.Web.Security;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using System.Web.UI.HtmlControls;

     

    using MyDelegateTest;

     

    public partial class Sort : System.Web.UI.Page

    {

         protected void Page_Load(object sender, EventArgs e)

         {

     

         }

         protected void Button1_Click(object sender, EventArgs e)

         {

             DelegateSample sample = new DelegateSample();

             sample.Items = GetItems();

     

             // 使用降序

             sample.Sort(new Compare(sample.Less));

     

             PrintItems(sample);

         }

     

         private void PrintItems(DelegateSample sample)

         {

             for (int i = 0; i < sample.Items.Length; i++)

             {

                  Response.Write(sample.Items[i] + "<br/>");

             }

         }

     

         private int[] GetItems()

         {

             string[] str = this.TextBox1.Text.Split(",".ToCharArray());

             int[] items = new int[str.Length];

             for (int i = 0; i < str.Length; i++)

                  items[i] = int.Parse(str[i]);

     

             return items;

         }

         protected void Button2_Click(object sender, EventArgs e)

         {

             DelegateSample sample = new DelegateSample();

             sample.Items = GetItems();

     

             // 使用升序

             sample.Sort(new Compare(sample.Greater));

     

             PrintItems(sample);

         }

    }

     

    效果图:

    降序



    升序


     

    参考资料:

    《.NET框架程序设计》

    《Visual Basic .Net Power Coding》

    展开全文
  • 委托

    千次阅读 2006-12-17 09:20:00
    委托是C#中的一种引用类型,类似于C/C++中的函数指针。与函数指针不同的是,委托是面向对象、类型安全的,而且委托可以引用静态方法和实例方法,而函数指针只能引用静态函数。委托主要用于 .NET Framework 中的事件...
     委托是C#中的一种引用类型,类似于C/C++中的函数指针。与函数指针不同的是,委托是面向对象、类型安全的,而且委托可以引用静态方法和实例方法,而函数指针只能引用静态函数。委托主要用于 .NET Framework 中的事件处理程序和回调函数。
    
           一个委托可以看作一个特殊的类,因而它的定义可以像常规类一样放在同样的位置。与其他类一样,委托必须先定义以后,再实例化。与类不同的是,实例化的委托没有与之相应的术语(类的实例化称作对象),作为区分我们将实例化的委托称为委托实例。
     一个函数在编译时被分配给一个入口地址,这个入口地址就称为函数的指针,正如同指针是一个变量的地址一样。
    函数指针的用途很多,最常用的用途之一是把指针作为参数传递到其他函数。我们可以参考下面的例子进一步理解函数指针作为参数的情况:
    客观的讲,使用函数指针作为其参数的函数如果直接调用函数或是直接把调用的函数的函数体放在这个主函数中也可以实现其功能。那么为什么还要使用函数指针呢?我们仔细看一下上面的main()函数就可以发现,main()函数两次调用了test函数,前一次求出最大最小值,后一次求出两数的和与差。如果我们test函数不用函数指针,而是采用直接在test函数中调用函数的方法,使用一个test函数还能完成这个功能吗?显然不行,我们必须写两个这样的test函数供main()函数调用,虽然大多数代码还是一样的,仅仅是调用的函数名不一样。上面仅仅是一个简单的例子,实际生活中也许main()函数会频繁的调用test(),而每次的差别仅仅是完成的功能不一样,也许第一次调用会要求求出两数的和与差,而下一次会要求求出最大值以及两数之和,第三次呢,也许是最小值和最大值,……,如果不用函数指针,我们需要写多少个这样的test()函数?显然,函数指针为我们的编程提供了灵活性。
    另外,有些地方必须使用到函数指针才能完成给定的任务,特别是异步操作的回调和其他需要匿名回调的结构。另外,像线程的执行,事件的处理,如果缺少了函数指针的支持也是很难完成的。
    类型安全
    从上面的介绍可以看出,函数指针的提出还是有其必要的,上面的介绍也同时说明了委托存在的必要性。那么为什么C#中不直接用函数指针,而是要使用委托呢?这就涉及到另外一个问题:C#是类型安全的语言。何谓类型安全?这里的类型安全特指内存类型安全,即类型安全代码只访问被授权可以访问的内存位置。如果代码以任意偏移量访问内存,该偏移量超出了属于该对象的公开字段的内存范围,则它就不是类型安全的代码。显然指针不属于类型安全代码,这也是为什么C#使用指针时必须申明unsafe的缘故。
    那么类型不安全代码可能会带来什么不良的后果呢?相信对于安全技术感兴趣的朋友一定十分熟悉缓冲区溢出问题,通过缓冲区溢出攻击者可以运行非法的程序获得一定的权限从而攻击系统或是直接运行恶意代码危害系统,在UNIX下这是一个十分普遍的问题。那么缓冲区溢出又和函数指针有什么关系呢?事实上,攻击者就是通过缓冲区溢出改变返回地址的值到恶意代码地址来执行恶意代码的。我们可以看看下面的代码:
    void copy()
                {
                     char buffer[128];
                     ........
                         strcpy (buffer,getenv("HOME"));//HOME为UNIX系统中的HOME环境变量
                     ........
                }
    上面的代码中如果HOME环境变量的字符数大于128,就会产生缓冲区溢出,假如这个缓冲区之前有另一个函数的返回地址,那么这一是地址就有可能覆盖,而覆盖这一地址的字符有可能就是恶意代码的地址,攻击者就有可能攻击成功了!
    上面的例子仅仅是指针问题中的一种,除此以外,还可能由于错误的管理地址,将数据写入错误地址,造成程序的崩溃;还可能由于对指针不恰当的赋值操作产生悬浮指针;还可能产生内存越界,内存泄漏等等问题。
    由此可见,指针不是类型安全的,函数指针当然也不例外,所以C#里面没有使用函数指针,而且不建议使用指针变量。
    委托
    前面的说明充分证明了委托存在的必要性,那么我们再谈谈为什么委托是类型安全的。C#中的委托和指针不一样,指针不通过MSIL而是直接和内存打交道,这也是指针不安全的原因所在,当然也是采用指针能够提高程序运行速度的缘故;委托不与内存打交道,而是把这一工作交给CLR去完成。CLR无法阻止将不安全的代码调用到本机(非托管)代码中或执行恶意操作。然而当代码是类型安全时,CLR的安全性强制机制确保代码不会访问本机代码,除非它有访问本机代码的权限。
    委托派生于基类System.Delegate,不过委托的定义和常规类的定义方法不太一样。委托的定义通过关键字delegate来定义:
    public delegate int myDelegate(int x,int y);
    上面的代码定义了一个新委托,它可以封装任何返回为int,带有两个int类型参数的方法。任何一个方法无论是实例方法还是静态方法,只要他们的签名(参数类型在一个方法中的顺序)和定义的委托是一样的,都可以把他们封装到委托中去。这种签名方法正是保证委托是类型安全的手段之一。
    产生委托实例和产生类实例(对象)差不多,假如我们有如下的方法:
    public int sub(int x,int y)
    {
           return(x+y);
    }
    我们就可以使用如下的代码得到一个委托实例:
    myDelegate calculatin=new myDelegate(sub);
    接下来我们就可以直接使用calculation调用sub方法了:
    calculation(10,3);
    下面我们将用委托重写上面的一个程序来看一下在C#中如何通过委托实现由函数指针实现的功能:
    我们还可以声明一个委托数组,就像声明一个对象数组一样,上面的例子中就使用到了委托数组;一个委托还可以封装多个方法(多路广播委托,经常与事件处理程序结合使用),只要这些方法的签名是正确的。多路广播委托的返回值一般为void,这是因为一个委托只能有一个返回值,如果一个返回值不为void的委托封装了多个方法时,只能得到最后封装的方法的返回值,这可能和用户初衷不一致,同时也会给管理带来不方便。如果你想通过委托返回多个值,最好是使用委托数组,让每个委托封装一个方法,各自返回一个值。
    事件
    在C#中,委托的最基本的一个用处就是用于事件处理。事件是对象发送的消息,以发信号通知操作的发生,通俗一点讲,事件就是程序中产生了一件需要处理的信号。
    事件的定义用关键字event声明,不过声明事件之前必须存在一个多路广播委托:
    public delegate void Calculate(int x,int y);//返回值为void的委托自动成为多路广播委托;
    public event calculate OnCalculate;
    从上节的委托实例和上面的事件的声明可以看出,事件的声明仅仅是比委托实例的声明多了个关键字event,事实上事件可以看作是一个为事件处理过程定制的多路广播委托。因此,定义了事件后,我们就可以通过向事件中操作符+=添加方法实现事件的预定或者是通过-=取消一个事件,这些都与委托实例的处理是相同的。与委托实例不同的是,操作符=对于事件是无效的,即
    OnCalculate=new calculate(sub) ;//无效
    只是因为上面的语句会删除由OnCalculate封装的所有其他方法,指封装了由此语句指定的唯一方法,而且一个预定可以删除其他所有方法,这会导致混乱。
    回调函数
    回调函数是在托管应用程序中可帮助非托管 DLL 函数完成任务的代码。对回调函数的调用将从托管应用程序中,通过一个 DLL 函数,间接地传递给托管实现。在用平台调用调用的多种
    展开全文
  • C# 委托 (一)—— 委托、 泛型委托与Lambda表达式

    万次阅读 多人点赞 2018-08-19 20:46:47
    1 委托的含义 2 委托声明、实例化和调用 2.1 委托的声明 2.2 委托的实例化 2.3 委托实例的调用 3 泛型委托 3.1 Func委托 3.2 Action委托 3.3 Predicate委托 4 匿名委托 5 Lambda表达式 5.1 表达式Lambda ...

    目录

    1 委托的含义

    2 委托声明、实例化和调用

    2.1 委托的声明

    2.2 委托的实例化

    2.3 委托实例的调用

    3 泛型委托

    3.1 Func委托

    3.2 Action委托

    3.3 Predicate委托

    4 匿名委托

    5 Lambda表达式

    5.1 表达式Lambda

    5.2 语句Lambda


    1 委托的含义

    当需要将一个方法当作另一个方法的参数时,对于某些语言例如C/C++等,需要用函数指针来处理。而对于C#来说,则使用委托机制。

    例如,当我们需要对一个泛型集合ICollection<T>进行排序时,我们定义一个Sort方法,那么这个方法需要哪些参数才能进行排序呢?首先,肯定需要一个Collection<T>对象作为输入参数,代表要排序的对象集合;然后,Sort方法还需要知道如何比较两个对象,经过比较之后才能决定让哪个对象排在前面。因此,Sort方法需要第二个参数,这个参数是一个方法,代表着比较排序对象的方法。这时候这个比较方法参数就只能是一个委托。我们在调用Sort方法对具体的类进行排序时,通过委托传入一个具体类的比较方法。

    再比如,在使用LINQ时,我们经常会用到Where()、Find()等扩展方法,实现对集合中元素的筛选或查找。Where()方法拥有一个Func<T>参数,它就是一个委托。我们调用Where()时需要给这个委托传递一个方法,告诉Where筛选器筛选元素的规则方法。

    委托是一种特殊的类,是一种能够引用方法的类。在创建委托时,就是创建了一个存储方法引用的对象。

    委托是类型安全的。C函数指针只是一个指向一个存储单元的指针,不能保证指向的内容就是正确类型的函数。而对于C#的委托而言,声明一个委托时必须指定返回类型和参数,.NET编译器会严格检查方法的参数和返回类型和委托是否匹配,检查通过后才能进行转换。转换之后的委托实例作为一个参数,传递给调用它的函数。

    一个委托可以被传递任何符合要求的方法。不同场合需要不同方法时,在调用的地方直接将委托参数替换为实际方法就行。因此,委托调用的方法是在程序运行时才能确定的。

    2 委托声明、实例化和调用

    2.1 委托的声明

    前面提到过,委托是一种特殊的类,因此委托的声明与类的声明方法类似,在任何可以声明类的地方都可以声明委托。委托声明用delegate关键字,同时委托要指明方法参数和返回值,写法与方法类似。综合类的声明和方法的声明,委托声明写成如下形式:

    [访问修饰符] delegate 返回值类型 委托名 (形参列表);

    委托的声明实际上是定义了一个派生于System.Delegate类的类,这与一般类的声明语法不同。编译器会根据委托的声明自动创建一个委托的类并实现细节。

    接下来我们以一个简单的List<Student>排序为例进行说明。假设我们有一个Student类,存放学生信息,拥有姓名、年龄和学号三个属性:

    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public int Num { get; set; }    
    }

    然后创建一个List<Student>:

    Student s1 = new Student() { Name = "小红", Age = 10, Num = 1001 };
    Student s2 = new Student() { Name = "小华", Age = 9, Num = 1002 };
    List<Student> sList = new List<Student>();
    sList.Add(s1);
    List.Add(s2);

    我们的目标是想给List<Student>对象添加一个排序方法,这个排序方法可以根据年龄或者学号来排序,具体需要哪一种排序需要在客户端调用时指定。(简单起见,本案例中List<Student>只包含两个元素,不纠结于排序算法)

    按照要求,Student对象的比较有两种方法,我们实现两个比较方法,供委托使用:

    //比较年龄
    public static bool Younger(Student s1, Student s2) => s1.Age <= s2.Age;
    
    //比较学号
    public static bool NumSmaller(Student s1, Student s2) => s1.Num <= s2.Num;

    由上,我们可以抽象出一个代表比较Student的方法的委托:

    public delegate bool CompareDelegate(Student first, Student second);

    这个委托的类名为CompareDelegate,注意到委托声明的返回值类型、参数与其代表的方法要完全一致。

    2.2 委托的实例化

    与普通类的使用方法相同,声明了委托之后,我们必须给委托传递一个具体的方法,才能在运行时调用委托实例。委托实例包含了被传递给它的方法的信息,在运行时,调用委托实例就相当于执行它当中的方法。

    委托实例化格式如下:

    委托类名 委托实例名 = new 委托类名(Target) ;

    其中,委托实例名是自定义的名称,Target是要传入的方法的名称。注意,Target是方法的引用,不能带()。带()的话是该方法的调用。区分引用和调用。

    委托的实例化还有一种简单的方法:

    委托类名 委托实例名 = Target;

    在需要委托实例的地方直接传入Target引用即可,C#编译器会自动根据委托类型进行验证,这称为“委托推断”。

    案例:

    //以下两种方法等价
    CompareDelegate myCompareDelegate = new CompareDelegate(Younger);
    CompareDelegate myCompareDelegate = Younger;//委托推断

    2.3 委托实例的调用

    委托实例等价于它当中实际方法,因此可以使用反射的Invoke()方法调用委托实例,也可以直接在委托实例后加上()进行调用。

    我们下面看一下委托所代表的方法是如何被业务方法调用的。这里我们的业务是排序SortStudent方法:

    //使用委托的业务方法
    public static void SortStudent(List<Student> sList, CompareDelegate CompareMethod)
    {
        if (CompareMethod(sList[0], sList[1]))//等价于CompareMethod.Invoke(sList[0],  List[1])
        {
            //sList[0]已经在sList[1]前面了,所以什么也不用做
        }
        else
        {
            sList.Reverse();//交换位置
        }
        //获取排名采用的比较方法的名称
        Console.WriteLine($"\r\n按照 {CompareMethod.Method.Name} 排名:");
        //打印排序后的链表
        foreach (Student s in sList)
            Console.WriteLine($"{s.Name} {s.Age} {s.Num} ");
    }

    这里Sort方法拥有一个CompareDelegate类型的委托实例CompareMethod,它可直接当做具体方法进行调用。

    在客户端对委托进行实例化后,调用SortStudent()方法就可以进行排序了。

    //委托的实例化与使用
    CompareDelegate myCompareDelegate = NumSmaller;//采用比较学号的方法
    SortStudent(sList, myCompareDelegate);
    
    //使用委托推断,与上两行等价
    SortStudent(sList, NumSmaller);

    输出如下:

    按照 NumSmaller 排名:
    小红 10 1001
    小华 9 1002

    3 泛型委托

    我们每次要使用一个委托时,都需要先声明这个委托类,规定参数和返回值类型,然后才能实例化、调用。为了简化这个过程, .NET 框架为我们封装了三个泛型委托类,因此大部分情况下我们不必再声明委托,可以拿来直接实例化使用,方便了我们的日常Coding。

    .这三种泛型委托包括:Func<T>委托、Action<T>委托和Predicate<T>委托。

    3.1 Func<T>委托

    Func<T>委托代表着拥有返回值的泛型委托。Func<T>有一系列的重载,形式如 Func<T1,T2, ... TResult>,其中TResult代表委托的返回值类型,其余均是参数类型。只有一个T时,即Func<TResult>,代表该委托是无参数的。.NET封装了最多16个输入参数的Funct<>委托。

    需要特别注意的是,若方法返回 void ,由于 void 不是数据类型,因此不能定义Func<void>委托。返回 void 的泛型委托见下文的Action<T>。

    Func<T>的使用方法与一般的委托相同。例如上面的案例可改写如下;

    public static void SortStudent(List<Student> sList,Func<Student,Student,bool> CompareMethod)
    {
        if(CompareMethod(sList[0], sList[1]))
        {
        }
        else
        {
            sList.Reverse();
        }
        Console.WriteLine($"\r\n按照 {CompareMethod.Method.Name} 排名:");
        foreach (Student s in sList)
            Console.WriteLine($"{s.Name} {s.Age} {s.Num} ");
    }
    
    //客户端调用
    Func<Student, Student, bool> myCompareFunc = NumSmaller;
    SortStudent2(sList, myCompareFunc);

    注意SortStudent2方法的委托参数也必须是Func<Student, Student, bool>,才能满足方法调用时类型一致的要求。 

    3.2 Action<T>委托

    Action<T>委托代表返回值为空 void 的委托,它也有一些列重载,最多拥有16个输入参数。用法与Func<T>相同。

    3.3 Predicate<T>委托

    这个一般用的较少,它封装返回值为bool类型的委托,可被Func<T>代替。

    4 匿名委托

    采用匿名方法实例化的委托称为匿名委托。

    每次实例化一个委托时,都需要事先定义一个委托所要调用的方法。为了简化这个流程,C# 2.0开始提供匿名方法来实例化委托。这样,我们在实例化委托时就可以 “随用随写” 它的实例方法。

    使用的格式是:

    委托类名 委托实例名 = delegate (args) {方法体代码} ;

    这样就可以直接把方法写在实例化代码中,不必在另一个地方定义方法。当然,匿名委托不适合需要采用多个方法的委托的定义。

    使用匿名方法,以上代码可改写为:

    CompareDelegate anonymousCompare = delegate (Student s3, Student s4) 
    { 
        return s1.Num <= s2.Num; 
    };
    SortStudent(sList, anonymousCompare);

    需要说明的是,匿名方法并不是真的“没有名字”的,而是编译器为我们自动取一个名字。SortStudent方法打印了委托调用的方法的名字(见上文代码),我们可以看到如下输出:

    按照 <Main>b__0 排名:
    小红 10 1001
    小华 9 1002

     编译器为我们的匿名方法取了一个b__0的名字。

    5 Lambda表达式

    江山代有才人出,纵然匿名方法使用很方便,可惜她很快就成了过气网红,没能领多长时间的风骚。如今已经很少见到了,因为delegate关键字限制了她用途的扩展。自从C# 3.0开始,她就被Lambda表达式取代,而且Lambda表达式用起来更简单。Lambda表达式本质上是改进的匿名方法。

    Lambda表达式的灵感可能是来源于数学中的函数表达式,例如下图:

    Lambda表达式把其中的箭头用 => 符号表示。

    如今Lambda表达式已经应用在很多地方了,例如方法体表达式(Expression-Bodied Methods)、自动只读属性表达式等等。

    Lambda表达式形式上分为两种:

    5.1 表达式Lambda

    当匿名函数只有一行代码时,可采用这种形式。例如:

    CompareDelegate LambdaCompare = (s4, s5) => s4.Age <= s5.Age;

    其中=>符号代表Lambda表达式,它的左侧是参数,右侧是要返回或执行的语句。参数要放在圆括号中,若只有一个参数,为了方便起见可省略圆括号。有多个参数或者没有参数时,不可省略圆括号。

    相比匿名函数,在表达式Lambda中,方法体的花括号{}和return关键字被省略掉了。

    其实,上文定义NumSmaller()和Younger()方法时,由于这两个方法主体只有一行代码,所以用的也是表达式Lambda,这是Lambda表达式的推广, 是C# 6 编译器提供的一个语法糖。

    5.2 语句Lambda

    当匿名函数有多行代码时,只能采用语句Lambda。例如,上面的表达式Lambda可改写为语句Lambda:

    CompareDelegate LambdaCompare = (s4, s5) => 
    {
        return s4.Age <= s5.Age;
    };

    语句Lambda不可以省略{}和return语句。

    展开全文
  • 合约策略委托类型说明 委托类型 计划委托 计划委托指令指的是预先设置委托和触发条件,当最新的成交价格达到事先设定的触发价格时,即会将事先设置的委托送入市场。 案例1:用户认为BTC的市场价格达到19250...

    合约策略委托类型说明

    委托类型

    计划委托

    计划委托指令指的是预先设置委托和触发条件,当最新的成交价格达到事先设定的触发价格时,即会将事先设置的委托送入市场。

    案例1:用户认为BTC的市场价格达到19250美元时,可能后续有较大的上涨行情,因此按照高于市场价19251美元委托开多。则您可以可以设置计划委托:
    这里写图片描述
    当市场价格达到了触发价格,若您设置的委托价此时触发了限价规则,那么系统会使用此时限价的最高价或者最低价进行下单。

    跟踪委托

    跟踪委托指的是在行情发生较大幅度回调的情况下,将客户事先设定的委托送入市场的策略。当市场的最新价格达到投资者设定该策略后最高(最低)市场价格的(1±客户设定回调幅度)后,即会触发客户设定的策略,将客户事先设定的委托送入市场中。

    案例1:当前BTC的市场价格为19000美元,某投资者判断BTC的市场价格还会继续下跌,但是在下跌后可能会出现反弹行情,因此用户希望在反弹幅度超过所设置的“回调幅度”,按照18000美元买入。因此可以设置跟踪委托:
    这里写图片描述
    当BTC市场价格从19000美元继续下跌,最低跌至17800美元,随后反弹上涨,若上涨至17999美元,此时回调幅度为(17999-17800)/17800=1.11%,但因为此时的市场价格17999美元<激活价格(18000美元),因此系统不触发此委托。若市场行情继续上涨到18000美元,则系统才触发此委托。
    总之,若买入,则需满足反弹幅度>=回调幅度,且市场价格>=激活价格,激活价格>=最低价格。
    若卖出,则需满足反弹幅度>=回调幅度,且市场价格<=激活价格,激活价格<=最低价格,才进行委托。

    冰山委托

    冰山委托指的是投资者在进行大额交易时,为避免对市场造成过大冲击,将大单委托自动拆为多笔委托,根据当前的最新买一/卖一价格和客户设定的价格策略自动进行小单委托,在上一笔委托被全部成交或最新价格明显偏离当前委托价时,自动重新进行委托。

    案例1:某客户希望按照19000美元买入BTC,但不希望过于影响盘面增加买入成本,此时其设置冰山委托:
    这里写图片描述
    此时系统将会自动为其进行冰山委托,每一笔委托的数量为其单次委托平均值的90%~110%,委托价格为最新买1价*(1-委托深度),在上一笔委托全部成交后再进行新的一笔委托,在最新成交价格距离该笔委托超过委托深度*2时自动撤单并重新进行委托。在策略总成交量等于其总委托数量时停止委托。当市场的最新成交价格高于“价格限制”即20000美元时停止委托,在最新成交价格重新低于20000美元后恢复委托。

    时间加权委托

    时间加权委托指的是客户希望大额交易BTC时,为避免过大冲击成本,通过策略将大单拆细为多个小额委托,根据最新的对手方委托量自动选择委托量,主动与对手方成交进行连续买入的策略。

    案例1:某客户希望买入1000张合约,此时其设置时间加权委托:
    这里写图片描述
    假设某一时刻的委托队列如下表:
    这里写图片描述
    按照客户设置的扫单范围,最高买入价格为当前买1价18726.93*(1+扫单范围1.0%)=18914.19美元,则统计所有低于18914.19美元的卖单总数量415+374+500+2+13=1304,根据客户设置的扫单比例,则该笔委托的数量=对手单数量*扫单比例=1304*5%=65.2个。此时系统自动进行委托:买入数量65.2个,委托价格18914.19的买单。所有未成交委托会在委托后立即撤销。根据客户设置的委托间隔,系统将会自动进行连续委托,直至策略的总成交量达到客户设置的总委托数量。当策略计算出的委托价格高于客户设定的最高买入价格时,系统将会自动按照客户设定的最高买入价格进行委托,若此价格无可成交对手单,则策略自动暂停,直至价格回到可成交范围内。当委托数量大于单笔委托上限时,以用户设置的单笔委托上限为委托数量进行委托。

    原文地址

    展开全文
  • 委托的作用和好处

    2020-07-19 19:35:02
    委托
  • C#委托

    2019-08-16 10:04:25
    在C#中的委托关键字是 Delegate,委托类似于C/C++中函数的指针。是存有对某个方法引用的引用类型变量,可在运行时被改变。一般用于实现事件和回调方法。 注意:所有的委托都派生自 System.Delegate 类 委托分为 ...
  • Activiti委托与解决委托

    千次阅读 2018-03-29 18:04:52
    Activiti委托与解决委托原创文章:转载请备注:原创文章地址前言:我觉得代码能看的懂得也就没必要看下面的的,所以先上代码:/** * 将指定任务进行委托处理 * * @param taskId * @param assignee */ public ...
  • unity委托

    千次阅读 2017-10-20 11:11:24
    unity委托
  • Kotlin 委托

    2019-03-01 11:36:39
    一、什么是委托? C#中有委托这么一说,但是在Java中是没有这么一说的。回到Kotlin中又有了委托。那到底什么是委托呢? 委托是软件设计的一种模式,当无法或不想访问某个对象或访问某个对象存在困难时,可以交给...
  • 委托及多播委托

    2016-07-21 17:27:42
    c#中的委托类似于c c++中的指针,委托就是概括了方法的签名和返回值类型 ,委托可以理解为定义的一个新的类。 所以在可以定义类的任何地方都可以定义委托,也可以在委托的定义上加访问修饰符 public private 等 1...
  • C# Action委托、Func委托

    千次阅读 2018-07-13 13:42:14
    如果我们要把方法当作参数传递的话就要用到委托。简单来说委托是一个类型,这个类型可以赋值一个方法的引用。一 . Action委托action委托指向的方法没有返回值c#代码如下:class ActionTest { void printStr() { ...
  • 事件委托

    千次阅读 2018-10-07 19:19:31
    网上的各位大牛们讲事件委托基本上都用了同一个例子,就是取快递来解释这个现象,我仔细揣摩了一下,这个例子还真是恰当,我就不去想别的例子来解释了,借花献佛,我摘过来,大家认真领会一下事件委托到底是一个什么...
  • delegate 委托关键字 如果我们要把方法当参数来传递的话,就要用到委托。简单来说委托是一个类型,这个类型可以赋值一个方法的引用。  在我们使用委托的时候,也需要两个阶段 ,和定义类差不多。  1 首先定义委托...
  • 委托——Action委托使用

    千次阅读 2018-09-01 11:13:39
    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;...namespace Action委托 { class Program { // **************************...
  • C#的委托和java里的委托

    千次阅读 2018-11-01 18:23:45
    C#:委托是方法的代理,委托的是方法,当调用委托时就调用了它的方法,是一类行为的抽象,是一种自定义数据类型。它有统一的返回类型和参数。1.定义委托:访问级别delegate 返回值 委托的名称(参数组成)delegate ...
  • C# 委托

    2017-10-26 09:46:39
    C# 委托实际上类似于C++中的函数指针,因为C#中不存在指针,所以用委托可以完成一些原来在C++中用函数指针完成的操作,例如传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,...
  • Unity 委托

    2018-12-26 13:24:03
    此文装载自: ... public class MyDelegate { public delegate void LogDelegate(string log); //定义 委托名为LogDelegate,带一个string参数的 委托类型 public static LogDelegate Log...
  • 委托之使用委托

    2014-03-08 11:49:24
    1.delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++." data-guid="4c1918af86104acb3cb0880cef46f9c0">委托是一种安全地封装方法的类型,它与 C 和 C++ 中的...

空空如也

1 2 3 4 5 ... 20
收藏数 66,838
精华内容 26,735
关键字:

委托