C#之委托

这篇具有很好参考价值的文章主要介绍了C#之委托。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、简介

(一)概述

(二)类与委托

二、声明委托

三、使用委托

(一)创建委托对象

(二)使用委托

四、简单的委托示例

五、Action[T]和Func[T]委托

六、多播委托

七、匿名方法


        委托时寻址方法的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项就无从知晓了。

        而.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含对多个方法的引用。

        Lambda表达式与委托之间相关。当参数是委托类型时,就可以使用Lambda表达式实现委托引用的方法。

一、简介

(一)概述

C#中的委托是一个类型,它描述了一个方法的签名,即方法的参数类型和返回类型。委托可以看作是一个指向方法的引用,使得我们可以像使用函数指针一样调用这些方法。

  • 将一个或多个方法作为参数传递给另一个方法,从而在需要时调用这些方法。
  • 实现事件处理程序。
  • 实现回调方法。
  • 实现异步编程等功能。

        我们习惯于把数据作为参数传递给方法,所以,给方法传递另一个方法听起来有点奇怪。而有时某个方法执行的操作并不是针对数据进行的,而是要对另一个方法进行操作。更麻烦的是,在编译时我们不知道第二个方法是什么,这个信息只能在运行时得到,所以需要把第二个方法作为参数传递给第一个方法。

        在C和C++中,只能提取函数的地址,并作为一个参数传递它。C没有类型安全性,可以把任何函数传递给需要函数指针的方法。但是,这种直接方法不仅会导致一些关于类型安全性的问题,而且没有意识到:在进行面向对象编程时,几乎没有方法是孤立存在的,而是在调用方法前通常需要与类实例相关联。所以.NET Framework在语法上不允许使用这种直接方法。如果要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊类型的对象,其特殊之处在于,我们以前定义的所有对象都包含数据,而委托包含的只是一个或多个方法的地址。

(二)类与委托

委托和类一样,是一种用户定义类型。但类表示的是数据和方法的集合,而委托则持有一个或多个方法,以及一系列预定义操作。可以通过一下操作步骤来使用委托。

(1)声明一个委托类型。委托声明看上去和方法声明相似,只是没有实现块。

(2)使用该委托类型声明一个委托变量

(3)创建一个委托类型的对象,并把它赋值给委托变量。新的委托对象包含指向某个方法的引用,这个方法的签名和返回类型必须跟第一步中定义的委托类型一致。

(4)你可以选择为委托对象添加其他方法。这些方法的签名和返回类型必须与第一步中定义的委托类型相同

(5)在代码中你可以像调用方法一样调用委托。在调用委托的时候,其包含的每一个方法都会被执行。

委托
声明类型 声明类 声明委托(类型)
声明类型的变量 声明类类型的变量 声明委托类型的变量
填充变量 创建类的实例并且把他的引用赋值给变量 创建委托的实例并且把它的引用赋值给变量,然后增加第一个方法
使用变量 使用类对象 调用委托对象

二、声明委托

在C#中使用一个类时,分两个阶段:

  • 需要定义这个类,即告诉编译器这个类由什么字段和方法组成。
  • 实例化类的一个对象

使用委托时,也需要经过这两个步骤:

  • 定义要使用的委托。对于委托,定义它就是告诉编译器这种类型的委托表示哪种类型的方法。
  • 必须创建该委托的一个或多个实例。编译器在后台将创建表示该委托的一个类。

定义委托的语法如下:

delegate void IntMethodInvoker(int x);

关键字:delegate        返回类型:void        委托类型名称:IntMethodInvoker        签名:int x

        

在这个示例中,定义了一个委托IntMethodInvoker,并指定该委托的每个实例都可以包含一个方法的引用,该方法带有一个int参数,并返回void。理解委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

假定要定义一个委托 TwoLongsop,该委托表示的方法有两个 long型参数,返回类型为 double。可以编写如下代码:

delegate double TwoLongsOp(long first, long second);
或者要定义一个委托,它表示的方法不带参数,返回一个string型的值,可以编写如下代码:
delegate string GetAString();

其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。因为定义委托基本是定义一个新类,所以可以在定义类的任何相同地方定义委托。也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在名称空间中把委托定义为顶层对象。更具定义的可见性,和委托的作用域,可以在委托的定义上应用任意常见的访问修饰符:public、private、protected等:

public delegate string GetAstring();

定义好委托后,就可以创建它的一个实例,从而用它存储特定方法的细节。

三、使用委托

(一)创建委托对象

委托是引用类型,因此有引用和对象。在委托类型声明之后,我们可以声明变量并创建类型的对象。

有两种声明委托的方式:

(1)使用带new运算符的对象创建表达式。new运算符的操作数的组成如下:

  • 委托类型名
  • 一组圆括号,其中包含作为调用列表中第一个成员的方法。该方法可以是实例方法也可以是静态方法
//创建委托并保存引用
GetAString delVar = new GetAString(myInstObj.MyM1);//实例方法
dVar = new MyDel(SClass.OtherM2); //静态方法

(2)还可以使用快捷语法,它仅由方法说明符构成

//创建委托并保存引用
delVar = myInstObj.MyM1;
dVar = SClass.OtherM2;

(二)使用委托

下面的代码段说明了如何使用委托。这是在int上调用 ToString 方法的一种相当冗长的方式:
private delegate string GetAString();
static void Main()
(
    int x = 40;
    GetAstring firstStringMethod = new GetAString(x.Tostring);
    Console.WriteLine("string is (0)", firstStringMethod());
    // With firststringMethod initialized to x.Tostring();
    // the above statement is equiva1ent to saying;
    // Console.WriteLine("string is {0}",x.ToString());
)

这段代码中,实例化了类型为GetAString的一个委托,对它进行初始化,使它引用整型变量x的 ToString()方法。在 C++中 ,委托在语法上是接受一个参数的构造函数,个参数就是委托引 用的方法。这个方法必须匹配最初定义委托时的签名。所以在这个示例中,如果用不带参数并返回 一个字符串的方法来初始化firstStringMethod变量,会产生一个编译错误。注意,因为int.ToString()是一个实例方法(不是静态方法),所以需要指定实(x)和方法名来正确地初始化委托。

下一行代码使用这个委托来显示字符串。在任何代码中,都应提供委托实例的名称,面的圆括号中应包含调用该委托中的方法时使用的任何等效参数。所以在上面的代码中Console.WriteLine() 语句完全等价于注释语句中的代码行。

四、简单的委托示例

在这个示例中,定义一个类MathsOperations,它有两个静态方法,对double类型的值执行两个操作,然后使用该委托调用这些方法。

class MathOperations
{
    public static double MultiplyByTwo(double value){
        return value * 2;
    }

    public static double Square(double value){
        return value * value;
    }
}

调用这些方法:

using System;
namespace wrox.ProCSharp.Delegates
{
    delegate double DoubleOp(double x);

    class Program
    {
        static void Main()
        {
            DoubleOp[] operations = 
            {
                MathOperation.MultiplyByTwo,
                MathOperations.Square
            };
            for(int i=0; i < operations.Length; i++)
            {
                Console.WriteLine("Using operations[(0)]:", i);
                ProcessAhdDisplayNumber(operations[i], 2.0);
                ProcessAndDisp1ayNumber(operations[i], 7.94;
                ProcessAndDisplayNumber(operations[i], 1.414);
                Console.WriteLine();
            }
        }
    
        static void ProcessAndDisplayNumber(DoubleOP action, double value)
        {
            double result = action(value);
            Console.WriteLine("Value is {0}, result of operation is {1}", value, result);
        }
    }
}

在这段代码中,实例化了一个委托数组DoubleOp(记住,一旦定义了委托类,基本上就可以实例化它的实例,就像处理一般的类那样——所以把一些委托的实例放在数组中是可以的)。该数组的每个元素都初始化为由MathOperations类实现的不同操作。然后遍历这个数组,把每个操作应用到3个不同的值上。这说明了使用委托的一种方式——把方法组合到一个数组中来使用,这样就可以再循环中调用不同的方法。

五、Action[T]和Func[T]委托

除了为每个参数和返回类型定义一个新类型之外,还可以使用Action<T>和Func<T>委托。

泛型Action<T>委托表示引用一个void返回类型的方法。因为这个委托类存在不同的变体,所以可以传递至多16种不同的参数类型。没有泛型参数的Action类可调用没有参数的方法。Action<in T>调用带一个参数的方法,Action<in T1,in T2>调用带两个参数的方法,Action<in T1,in T2......in T8>调用带8个参数的方法。

Func<T>委托可以以类似的方式使用。Func<T>允许调用带返回类型的方法。与Action<T>类似,Func<T>也定义了不同的变体,至多也可以传递16个参数类型和一个返回类型。Func<out TResult>委托类型可以调用带返回类型且无参数的方法,Func<in T,out TResult>调用带一个参数的方法,Func<in T1,in T2,in T3,in T4,out Tresult>调用带4个参数的方法。

六、多播委托

前面使用的每个委托都只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显式调用这个委托。但是,委托也可以包含多个方法。这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此委托的签名就必须返回void,负责就只能得到委托调用的最后一个方法的结果。

可以使用返回类型为void的Action<double>委托:

class Program
{
    static void Main()
    {
        Action<double> operations = MathOperations.MultiplyByTwo;
        operations += MathOperations.Square;
    }
}

因为要存储对两个方法的引用,所以实例化了一个委托数组。而这里只有在同一个多播委托中添加两个操作。多播委托可以识别运算符“+”和“+=”。还可以扩展上述代码中的最后两行:

Action<double> operation1 = MathOperations.MultiplyByTwo;
Action<double> operation2 = MathOperations.Square;
Action<double> operations = operation1 + operation2;

多播委托还能识别运算符“-”和“-=”,以从委托中删除方法的调用。

七、匿名方法

 到目前为止,要想使委托工作,方法必须已经存在(即委托是用它将调用的方法的相同签名定义的)。但还有另外一种使用委托的方法:即通过匿名方法。匿名方法是用作委托的参数的一段代码。

用匿名方法定义委托的语法与前面的定义并没有区别。但在实例化委托时,就有区别了。

using System;

namespace Wrox.ProCSharp.Delegates
{
    class Program
    {
        static void Main()
        {
            string mid = ",middle part,";
            Func<String, String> anonDel = delegate(string param)
            {
                param += mid;
                param += "and this was added to the string.";
                return param;
            };
            Console.WriteLine(anonDel("Start of string"));
        }
    }
}

Func<string, string>委托接受一个字符串参数,返回一个字符串。annonDel是这种委托类型的变量。不是把方法名赋予这个变量,而是使用一段简单的代码:他前面是关键字delegate,后面是一个字符串参数。

可以看出,该代码块使用方法级的字符串变量mid,变量是在匿名方法的外部定义的,把它添加到要传递的参数中。接着代码返回该字符串值。在调用委托时,把一个字符串作为参数传递, 将返回的字符串输出到控制台上。

匿名方法的优点是减少了要编写的代码。不必定义仅由委托使用的方法。这有助于降低代码的复杂性,尤其是定义了好几个事件时,代码会显得比较简单。

在使用匿名方法时,必须遵循两条规则。在匿名方法中不能使用跳转语句break、 goto或 continue) 跳到该匿名方法的外部,反之亦然:名方法外部的跳转语旬不能跳到该匿名方法的内部。 在匿名方法内部不能访问不安全的代码。另外,也不能访问在匿名方法外部使用的 ref和 out参数。但可以使用在匿名方法外部定义的其他变量。文章来源地址https://www.toymoban.com/news/detail-799745.html

到了这里,关于C#之委托的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c#委托详解

    委托是一种能够将方法作为参数传递、存储方法并且调用方法的类型,它可以让我们写出更加灵活和可扩展的代码。委托通常用于回调 (Callback) 机制,比如在事件处理、异步编程、LINQ 查询等场景中常常会使用委托。它可以将方法作为参数传递给其他方法,从而在需要的时候

    2023年04月08日
    浏览(28)
  • C#基础--委托

    C#基础–委托 简单说它就是一个能把方法当参数传递的对象,而且还知道怎么调用这个方法,同时也是粒度更小的“接口”(约束了指向方法的签名) 跟方法有点类似,有参数,返回值,访问修饰符+ delegate 委托的本质是一个类,继承自一个特殊类 MulticastDelegate ,我们自己在

    2024年02月16日
    浏览(41)
  • C# 常量 结构体 委托

    常量名命名一般使用大写字母 开发一个游戏,游戏角色有法师(Mage)、射手(Archer)、刺客(Assassin)、坦克(Tank)、铺助(Support)、战士(Warrior),等不同类型。 ❓如何存储游戏角色 使用 int 类型 :创建一套规则,提前为各个类型角色绑定一个数字标识 使用枚举类型 什么是枚举类型?

    2024年02月02日
    浏览(30)
  • C#的Func(委托)

    在 C# 中,Func 是一个泛型委托类型,用于表示一个具有返回值的方法或 lambda 表达式。 Func 可以接受 0~16 个输入参数,其最后一个泛型参数表示返回值类型。例如,Func 表示一个不接受参数,返回整数类型的方法。 以下是一个 Func 的简单例子: 在上面的例子中,我们创建了一

    2024年02月15日
    浏览(44)
  • C#——委托

    什么是委托        C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。 声明委托          委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。  

    2023年04月15日
    浏览(29)
  • 委托与事件(一)——C#版本

      委托是对 函数的封装 ,可以当作给方法的特征指定一个名称。而事件则是 委托的一种特殊形式 ,当发生有意义的事情时,事件对象处理通知过程。   委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有 完全相同的行为 。   用例子来说明为

    2023年04月09日
    浏览(43)
  • C#匿名方法增加、删除委托

    匿名方法给我们带来了方便,那么如何增加删除匿名方法中附加的委托(事件)呢 一般写法: 1 2 3 4 this .Loaded += (sender, e) =       {              //Do something       }; 进化写法: 1 2 3 4 5 6 7 this .Loaded += new   RoutedEventHandler(FormulaAssign_Loaded); void   FormulaAssign_Loaded( objec

    2024年02月11日
    浏览(34)
  • C#委托和事件简单复习

    太久没用了,简单的复习一下 快速过一遍语法使用 1.定义一个委托类型 只需要在声明的前面加上delegate,其他的就跟声明一个方法(函数)类似 2.使用刚刚声明的委托 需要定义一个返回值跟参数与我们刚刚定义的委托一致 3.然后声明一个SayHello类型(委托)的变量 把

    2024年02月14日
    浏览(43)
  • Unity学前C#:委托详解

    字面意思就是:这件事情我不亲自去做,而是委托别人去做 C#中的委托有点类似c/c++中的函数指针,但是C#中的委托就可以看作是函数指针的升级版 以下是c/c++的函数指针实例  先理解一个概念: 一切皆地址 在计算机中所有的程序以及数据的存储都是有地址可循的,计算机组成原理

    2024年03月19日
    浏览(44)
  • C#学习笔记8:接口、委托、事件

    今日继续我的C#学习之路,今日学习接口、委托、事件,文章从实践出发学习这三个设计理念,并提供完整源码 目录 1、接口(多重继承): 代码: 运行结果: 2、委托(方法的代理/函数指针): 创建控制台程序实现委托: 遇到的报错及解决: 修改后的代码: 运行结果: 3、

    2024年04月15日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包