C#委托详解

C#中的委托类似C、C++中的函数指针。使用委托,程序员可以将方法引用封装在委托对象类。然后可以将该委托对象传递给可调用所引用方法的代码,而不必再编译时知道将调用哪个方法。委托时一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托时定义回调方法的理想选择。
与c和c++的函数指针不同,委托时面向对象、类型安全的。

1、委托的声明

两个步骤:
    首先定义要使用的委托,即告诉编译器这种类型的委托代表了哪种类型的方法。
    然后创建该委托的一个或多个实例。
    其定义语法为:  delegate void IntMethodInvoker(int a);
    上面这句话表明,定义了一个委托IntMethodInvoker,并指定该委托的每个实例都包含一个方法细节,该方法带有一个int参数,并且返回值为void

    实际上定义一个委托就是定义一个”新类“。它可以定义在任何地方。

2、委托的使用

    例子如下:
  
  private delegate string GetString();//此处定义一个没有参数,且返回值为string的委托
        static void Main(string[] args)
        {
            int x = 23;
            //GetString firstString = new GetString(x.ToString);
            //上一句也等价于下一句,但是注意不能写成GetString firstString = x.ToString();
            GetString firstString = x.ToString;//这为委托推断
            Console.WriteLine("String is {0}", firstString());
            //上一句中firstString()等价于x.ToString()方法
            Console.ReadLine();
        }

注意:不能调用x.ToString()方法把它传递给委托变量,因为调用该方法返回的事一个能赋予委托变量的字符串对象,只能该方法的地址赋予委托变量。

3、委托示例

class test
    {
        public static double MultiplyByTwo(double value)
        {
            return value * 2;
        }
        public static double Square(double value)
        {
            return value * value;
        }
    }
    delegate double DoubleOperation(double x);
    class Program
    {
        static void Main(string[] args)
        {
            DoubleOperation[] operations = { test.MultiplyByTwo, test.Square };
            for (int i = 0; i < operations.Length;i++ )
            {
                Console.WriteLine("Using operations[{0}]:", i);
                display(operations[i], 2.0);
                display(operations[i], 7.94);
                display(operations[i], 1.233);
                Console.WriteLine();
            }
            Console.ReadLine();
        }
        static void display(DoubleOperation action, double value)
        {
            double result = action(value);
            Console.WriteLine("Value is {0},result of operation is{1}", value, result);
        }
    }


输出结果为:

这段代码实例化了一个委托数组,并用两个函数签名符合的函数填充了该数组(就好比实例化类一样),然后分别取出这委托的这两个实例将其传递给另一个方法调用。
operations[i]表示这个委托,即这个委托代表的方法
operations[i](2.23)表示调用这个方法,参数放在括号中。

4、多播委托

多播委托允许把多个方法调用链接起来,成为一个列表。然后依次调用,一般委托的签名必须返回为void,不然就只能得到委托调用的最后一个方法的结果了。多播委托可以识别+、+=,-、-=等运算符。

多播委托示例如下:
class test
    {
        public static void one(double value)
        {
            double result = value * 2;
            Console.WriteLine("One  :   the value is {0}, give you {1},",value,result);
        }
        public static void two(double value)
        {
            double result = value * value;
            Console.WriteLine("Two  :   the value is {0}, give you {1},", value, result);
        }
    }

    delegate void DoubleOperation(double value);//定义委托

    class Program
    {
        static void Main(string[] args)
        {
            DoubleOperation opreations = test.one;//实例化委托
            opreations += test.two;
            display(opreations, 2.0);
            display(opreations, 7.94);
            display(opreations, 1.233);
            Console.ReadLine();
        }

        static void display(DoubleOperation action, double value)
        {
            Console.WriteLine();
            action(value);//该语句会按顺序调用action委托实例中的方法。
        }
    }


输出结果为:

使用多播委托应注意:
对同一个委托调用方法链的顺序并未正式定义,因此应避免编写依赖于以特定顺序调用方法的代码。
多播委托包含一个逐个调用的委托集合,如果通过委托调用的一个方法抛出异常,则整个迭代就会停止。即只执行了异常前的方法,停止在抛异常的方法那儿,之后的方法不再执行。
解决这个方法我们可以将委托链利用Delegate类定义的方法GetInvocationList()方法将其转换为Delegate对象数组,并循环一次执行相关方法,捕捉异常后,可继续下一次迭代。
如:
static void main()
{
    DemoDelegate dl = one;
    dl+=two;
    Delegate[] delegates=dl.GetInvocationList();
    foreach(DemoDelegate d in delegates)
    {
        try    
        {
            d();
        }
        catch(Exception)
        {
                    Console.WriteLine("Exception caught");
        }
    }
}


5、匿名委托

    定义匿名委托时与前面相同,实例化时则不是传送已知的方法名,而是使用一个简单的代码块,它前面的关键字为delegate,后面括号中跟参数,大括号中跟实现代码。即:delegateName  test = delegate(string param){代码};//delegareName为定义的委托,test为该委托的实例
使用匿名方法应注意:
  •  匿名方法不能使用跳转语句跳到该匿名方法的外部,也不能从外部跳到匿名方法的内部。
  • 在匿名方法中不能访问不安全的代码。
  • 不能访问在匿名方法外部使用的ref和out参数化,当可以访问外部定义的其他变量
  • 若要多次编写同一个功能的的方法,就不要用匿名方法。
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值