1.引用方法

函数指针是一个指向内存位置的指针,不是类型安全的。无法判断实际指向。参数和返回类型也无从知晓。
.NET委托是类型安全的。定义了返回类型和参数类型,不仅包含方法引用,还可以包含多个方法引用。

2.委托

使用方法作为参数进行传递,必须把方法细节进行封装到一个新类型的对象中,即委托。
委托是一种特殊类型的对象。我们之前定义的对象都包含数据。而委托包含的是多个方法的地址。

声明委托

委托使用delegate声明。通过指定返回类型、签名以及参数类型进行创建。

创建委托的一个或多个实例,编译器将在后台创建表示该委托的一个类。

delegate void InitMethodInvoker(int x);

该委托方法无返回值,参数类型是int,每个实例都会有这个方法的引用。该委托类似于方法的定义,没有方法体。

委托可以使用访问修饰符进行修饰:

private delegate void InitMethodInvoker(int x);

定义委托后,创建它的实例,从而实现它的细节即方法体。

使用委托
class MathOperations
    {
        public static double MultiplayByTwo(double value)
        {
            return value * 2;
        }

        public static double Square(double value)
        {
            return value * value;
        }
    }
//这个类中定义了委托的实例
public delegate double DoubleOp(double x);//声明委托
static void Main(string[] args)
{
     DoubleOp[] operations = 
     {
         MathOperations.MultiplayByTwo,//指定委托实例方法
         MathOperations.Square
     };
     for (int i = 0; i < operations.Length; i++)
     {
      //将委托实例方法作为参数传递 ProcessAndDisplayNumber(operations[i],
2.0);//operations[i]是委托即方法参数 ProcessAndDisplayNumber(operations[i], 15); } } static void ProcessAndDisplayNumber(DoubleOp action,double value) { double result = action( value);//实现委托 Console.WriteLine("参数值value:" + value + ",结果值result:" + result); }

通常情况下需要做安全措施。如果这个方法使用DoubleOp委托实例方法作为参数传递,如果传入null值,到了action( value)会出现异常。因此需要在方法里面加上判断

ProcessAndDisplayNumber(null, 15);
static void ProcessAndDisplayNumber(DoubleOp action,double value)
{
  if(action!=null)
     double result = action( value);//实现委托
   Console.WriteLine("参数值value:" + value + ",结果值result:" + result);
}
系统委托

系统委托有4中:Action类、Func类、Predicate<T>、Comparison<T>委托

Action类的委托
  1. Action委托 封装一个方法,该方法不具有参数并且不返回值
  2. Action<T>委托 封装一个方法,该方法只有一个参数并且不返回值

  3. Action<T1,T2>委托 封装一个方法,该方法具有两个参数并且不返回值
  4. C#高级编程9-第8章 委托、lamdba表达式和事件
    static void Main(string[] args)
    {
      #region Action<T>委托示例
      //需求:打印出整型集合list的元素
      List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
      //将匿名方法分配给 Action<T> 委托实例
      Action<int> concat1 = delegate(int i) { Console.WriteLine(i); };
      list.ForEach(concat1);
      //将 lambda 表达式分配给 Action<T> 委托实例
      Action<int> concat2 = (i => Console.WriteLine(i));
      list.ForEach(concat2);
      Console.ReadKey();
      #endregion 
    }
    C#高级编程9-第8章 委托、lamdba表达式和事件

Func类的委托

  1. 1.Func(TResult)委托封装封装一个不具有参数但却返回 TResult 参数指定的类型值的方法
  2. Func(T,TResult)委托 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法
  3. Func(T1,T2,TResult)委托 封装一个具有两个参数并返回 TResult 参数指定的类型值的方法
  4. C#高级编程9-第8章 委托、lamdba表达式和事件
    static void Main(string[] args)
    {
      #region Func<T,TResult>委托示例
      //需求:查找整型集合list中大于3的所有元素组成的新集合,并打印出集合元素
      List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
      //将匿名方法分配给 Func<T,TResult> 委托实例
      Func<int, bool> concat1 = delegate(int i) { return i > 3; };
      var newlist1 = list.Where(concat1).ToList();
      //将 Lambda 表达式分配给 Func<T,TResult> 委托实例
      Func<int, bool> concat2 = i => i > 3;
      var newlist2 = list.Where(concat2).ToList();
      newlist1.ForEach(i => Console.WriteLine(i.ToString()));
      newlist2.ForEach(i => Console.WriteLine(i.ToString()));
      Console.ReadKey();
      #endregion
    }
    C#高级编程9-第8章 委托、lamdba表达式和事件

Predicate<T>委托

    表示定义一组条件并确定指定对象是否符合这些条件的方法

  1. C#高级编程9-第8章 委托、lamdba表达式和事件
    static void Main(string[] args)
    {
      #region Predicate<T>委托示例
      //需求:查找整型集合list中大于3的所有元素组成的新集合,并打印出集合元素
      List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
      //将匿名方法分配给 Predicate<T> 委托实例
      Predicate<int> concat1 = delegate(int i) { return i > 3; };
      var newlist1 = list.FindAll(concat1);
      //将 lambda 表达式分配给 Predicate<T> 委托实例
      Predicate<int> concat2 = (c => c > 3);
      var newlist2 = list.FindAll(concat2);
      newlist1.ForEach(i => Console.WriteLine(i));
      newlist2.ForEach(i => Console.WriteLine(i));
           Console.ReadKey();
      #endregion
    }
    C#高级编程9-第8章 委托、lamdba表达式和事件

Comparison<T>委托

   表示比较同一类型的两个对象的方法

  • C#高级编程9-第8章 委托、lamdba表达式和事件
    static void Main(string[] args)
    {
      #region Comparison<T>委托示例
      //需求:将整型集合list中的所有元素倒序排列打印出来
      List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
      //将匿名方法分配给 Comparison<T> 委托实例
      Comparison<int> concat1 = delegate(int i, int j) { return j - i; };
      //将 lambda 表达式分配给 Comparison<T> 委托实例
      Comparison<int> concat2 = (i, j) => j - i;
      list.Sort(concat1);
      list.ForEach(c => Console.WriteLine(c.ToString()));
      list.Sort(concat2);
      list.ForEach(c => Console.WriteLine(c.ToString()));
           Console.ReadKey();
      #endregion
    }
    C#高级编程9-第8章 委托、lamdba表达式和事件
BubbleSorter

说明了委托真正的意图,首先定义一个Employee类,类中定义静态方法CompareSalary

public static bool CompareSalary(Employee e1, Employee e2)
{
      return e1.Salary < e2.Salary;
}

然后我们再定义一个类BubbleSorter,类中定义静态方法Sort

static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
        {
            bool swapped = true;
            do
            {
                swapped = false;
                for (int i = 0; i < sortArray.Count - 1; i++)
                {
                    if (comparison(sortArray[i + 1], sortArray[i]))
                    {
                        T temp = sortArray[i];
                        sortArray[i] = sortArray[i + 1];
                        sortArray[i + 1] = temp;
                        swapped = true;
                    }
                }
            } while (swapped);
        }

接下来我们分析一下:

Func<T, T, bool>是系统定义的委托,该委托具有2个参数,一个返回值,委托参数类型T根据调用Sort方法时进行指定(BubbleSorter.Sort<Employee>(..,..,))。然后我们看看所有执行代码:
static void Main()
        {
            Employee[] employees =
            {
                new Employee("Bugs Bunny", 20000),
                new Employee("Elmer Fudd", 10000),
                new Employee("Daffy Duck", 25000),
                new Employee("Wile Coyote", 1000000.38m),
                new Employee("Foghorn Leghorn", 23000),
                new Employee("RoadRunner", 50000)
            };
//将Employee.CompareSalary方法作为参数进行传递,记住Employee.CompareSalary是一个委托实例类型,它目前不属于Func<T, T, bool>的实例,但是
//它符合Func<T, T, bool>类型,因此可以作为Func<T, T, bool>的实例进行参数传递。
      BubbleSorter.Sort(employees, Employee.CompareSalary);
      foreach (var employee in employees) 
      {
        Console.WriteLine(employee);
      }
}

 

多播委托

委托可以包含多个方法,可以多次显式调用这个委托。

需要注意的是,多播委托需要连续的调用多个方法,并且委托的返回结构是void,否则就只能得到最后一个方法的结果。

可以使用“+=”或者“-=”添加和删除方法。

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);
    }
  }
View Code

相关文章:

  • 2022-12-23
  • 2021-11-02
  • 2021-11-20
  • 2021-08-20
  • 2022-12-23
  • 2021-12-27
猜你喜欢
  • 2021-09-02
  • 2021-08-11
  • 2022-12-23
  • 2021-09-15
  • 2022-12-23
  • 2021-11-09
  • 2022-12-23
相关资源
相似解决方案