博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C#语言学习之旅(6)--委托

Posted on 2013-01-09 11:55  米粒3  阅读(239)  评论(0编辑  收藏  举报
 

本章节主要讲解委托内容,最后顺便讲下C#事件。

C#中的委托,其实和c++中的回调函数差不多的,都是回调方法。

6.1 委托定义

 当在C#中我们想把方法传送给其他方法时候,我们就需要使用委托。一般委托主要用在写通用库类、事件以及线程这几个方面。

C#定义委托中声明

 delegate void DelegateDmop();

在上面的语法表示定义了一个委托DelegateDemo,并制定该委托的每个实例都包含一个方法,该方法没有参数,并返回值为void。

理解委托的一种好方法是把委托当中给方法签名和返回类型指定名称。

下面给出委托一个最简单的例子。

delegate简单实例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace delegateDemo
{
    
class Program
    {
        
delegate string DelegateSimpleDemo();//定义委托
        static void Main(string[] args)
        {
            
int x = 44;
            
//实例化委托,并且进行初始化ToString方法作为参数
            DelegateSimpleDemo firstDemo = new DelegateSimpleDemo(x.ToString);//

            Console.WriteLine(
"this is a simple "+firstDemo());
            
        }
    }
}

 给定的委托实例可以表示任何类型的任何对象上的实例方法或静态方法--只要方法的签名匹配于委托的签名即可

为了证明上面这一点,给出个例子来:

delgate示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace delegateDemo
{
    
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}", Dollars, Cents);
        }

        
public static string GetCurrencyUnit()
        {
            
return "Dollar";
        }

    }
    
class Program
    {
        
//delegate string DelegateSimpleDemo();//定义委托

        
private delegate string GetAString();
        
static void Main(string[] args)
        {
            
//int x = 44;
            ////实例化委托,并且进行初始化ToString方法作为参数
            //DelegateSimpleDemo firstDemo = new DelegateSimpleDemo(x.ToString);//

            
//Console.WriteLine("this is a simple "+firstDemo());

            
//simple
            int x = 44;
            GetAString firstMethod 
= x.ToString;
            Console.WriteLine(
"string is " + firstMethod());

            Currency balance 
= new Currency(3450);

            
//引用一个对象
            firstMethod = new GetAString(balance.ToString);
            Console.WriteLine(
"String is " + firstMethod());

            
//引用静态方法
            firstMethod = new GetAString(Currency.GetCurrencyUnit);
            Console.WriteLine(
"String is a static " + firstMethod());


        }
    }
}

 6.2 委托数组

下面给出一个例子来说明如何把委托传递给方法,如何使用委托数组。

委托数组
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

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

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

  
    
class Program
    {

        
delegate double DoubleOp(double x);

        
static void Main(string[] args)
        {

            DoubleOp[] operations 
=
            {
                MathOperations.MultiplyByTwo,
                MathOperations.Square
                
//new DoubleOp(MathOperations.MultiplyByTwo);
                
//new DoubleOp(MathOperations.Square);
            };

            
for (int i = 0; i < operations.Length;i++)
            {
                Console.WriteLine(
"Using operations[{0}]", i);
                ProcessAndDisplayNumber(operations[i], 
2.0);
                ProcessAndDisplayNumber(operations[i], 
7.94);
                ProcessAndDisplayNumber(operations[i], 
1.414);

            }


           

        }
        
static void ProcessAndDisplayNumber(DoubleOp Action, double values)
        {
            
//调用Action委托实例封装的方法 
            double result = Action(values);
            Console.WriteLine(
"Values is {0},result of Operation is {1}", values, result);
        }

    }
}

 说明:当实例化了一个委托数组后就可以像处理类一样,来随意调用不同的方法了。operation[i]表示委托代表的方法。operation[i](2.0)表示调用这个方法,参数为2.0.

6.3 使用委托实现通用类库

比如我们常见的冒泡排序来实现一个Sort(),一般非常适合int排序,但是万一我们希望Sort方法能够对任何对象排序怎么办呢。这个时候我们就可以使用委托来解决这个问题,

实现通用库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace delegateDemo
{
    
//申明委托
    public delegate bool Comparsion(object x, object y);


    
//冒泡排序
    public class MySort
    {
        
public static void Sort(object[] sortArray, Comparsion comparer)
        {
            
for (int i = 0; i < sortArray.Length; i++)
            {
                
for (int j = i + 1; j
                    
< sortArray.Length; j++)
                {
                    
if (comparer(sortArray[j], sortArray[i]))
                    {
                        
object temp = sortArray[i];
                        sortArray[i] 
= sortArray[j];
                        sortArray[j] 
= temp;
                    }
                }
            }
        }
    }

     
class Employee
    {
        
private string name;
        
private decimal salary;

        
public Employee(string name, decimal salary)
        {
            
this.name = name;
            
this.salary = salary;
        }

         
//重载
        public override string ToString()
        {
            
return string.Format("{0}, {1:C}", name, salary);
        }

         
//委托具体实现方法
        public static bool CompareSalary(object x, object y)
        {
            Employee e1 
= (Employee)x;
            Employee e2 
= (Employee)y;
            
return (e1.salary < e2.salary);
        }
    }


    
class Program
    {

        
static void Main(string[] args)
        {

            Employee[] employees 
=
                 {
                   
new Employee("Bugs Bunny"20000),
                   
new Employee("Elmer Fudd"10000),
                   
new Employee("Daffy Duck"25000),
                   
new Employee("Wiley Coyote", (decimal)1000000.38),
                   
new Employee("Foghorn Leghorn"23000),
                   
new Employee("RoadRunner'"50000)
                 };

            MySort.Sort(employees,Employee.CompareSalary);

            
foreach (var employee in employees)
            {
                Console.WriteLine(employee);
            }

        }
    }
}

 说明:实现上面通用库,只需要知道委托中传递的是什么方法,封装这个方法就可以了。

6.4 多播委托

多播委托就是一个委托可以包含多个方法。如果调用多播委托,就可以按顺序连续调用多个方法。所以,委托的签名就必须返回void;否则只能得到委托调用的最后一个方法的结果。

多播委托示例
using System;
using System.Collections.Generic;
using System.Text;

namespace MulticastDelegate
{
   
delegate void DoubleOp(double value);

   
class MathOperations
   {
      
public static void MultiplyByTwo(double value)
      {
         
double result = value * 2;
         Console.WriteLine(
            
"Multiplying by 2: {0} gives {1}", value, result);
      }

      
public static void Square(double value)
      {
         
double result = value * value;
         Console.WriteLine(
"Squaring: {0} gives {1}", value, result);
      }
   }


   
class Program
   {

      
static void ProcessAndDisplayNumber(DoubleOp action, double valueToProcess)
      {
         Console.WriteLine(
"\nProcessAndDisplayNumber called with value = " +
                            valueToProcess);
         action(valueToProcess);
      }

      
static void Main()
      {
         DoubleOp operations 
= MathOperations.MultiplyByTwo;
         operations 
+= MathOperations.Square;

         ProcessAndDisplayNumber(operations, 
2.0);
         ProcessAndDisplayNumber(operations, 
7.94);
         ProcessAndDisplayNumber(operations, 
1.414);
         Console.WriteLine();

      }
   }
}

 说明:在本例中只是用了+=,还可以识别+,-和-=以从委托中删除方法调用。特别注意,委托签名返回值要为void。

6.5 多播委托处理异常问题

 当多播委托出现异常的时候,无法确认是哪个委托出现异常,该怎么办呢。为了避免这个问题,我们可以来迭代方法列表来解决这个问题。Delegate类定义了方法GetInvocationList(),他返回一个Delegate对象数组,我们可以操作里面的对象。

多播异常处理
using System;

namespace Wrox.ProCSharp.Delegates
{
   
class Program
   {
      
static void One()
      {
         Console.WriteLine(
"One");
         
throw new Exception("Error in one");
      }

      
static void Two()
      {
         Console.WriteLine(
"Two");
      }

      
public delegate void DemoDelegate();

      
static void Main()
      {
         DemoDelegate d1 
= One;
         d1 
+= Two;

         Delegate[] delegates 
= d1.GetInvocationList();
         
foreach (DemoDelegate d in delegates)
         {
            
try
            {
               d();
            }
            
catch (Exception)
            {
               Console.WriteLine(
"Exception caught");
            }

         }

      }
   }
}

 说明:通过迭代可以实现每个方法的遍历了。

 小结:这一章节例子比较多,弄了很久,下一章节将写一些关于字符串和正则表达式内容