C#--泛型委托Action、Func、Predicate的解析和用法

C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托是保存对某个方法引用的一种引用类型变量。

若要引用的方法,具有两个参数没有返回值,使用Action委托,则不需要显式定义委托。Action委托还有很多重载,根据参数的个数,选择不同的方法重载。

C#--泛型委托Action、Func、Predicate的解析和用法_第1张图片

若要引用的方法,具有两个参数并返回一个值,使用泛型Func委托,则不需要显式定义委托。Func委托还有很多重载,根据参数的个数,选择不同的方法重载。

C#--泛型委托Action、Func、Predicate的解析和用法_第2张图片

一、使用delegate定义没有返回值的委托:

using System;
using System.IO;

delegate void ConcatStrings(string string1, string string2);

public class TestDelegate
{
   public static void Main()
   {
      string message1 = "The first line of a message.";
      string message2 = "The second line of a message.";
      ConcatStrings concat;

      if (Environment.GetCommandLineArgs().Length > 1)
         concat = WriteToFile;
      else
         concat = WriteToConsole;

      concat(message1, message2);
   }

   private static void WriteToConsole(string string1, string string2)
   {
      Console.WriteLine("{0}\n{1}", string1, string2);            
   }

   private static void WriteToFile(string string1, string string2)
   {
      StreamWriter writer = null;  
      try
      {
         writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);
         writer.WriteLine("{0}\n{1}", string1, string2);
      }
      catch
      {
         Console.WriteLine("File write operation failed...");
      }
      finally
      {
         if (writer != null) writer.Close();
      }      
   }
}

使用Action委托,则不需要显式定义委托:

using System;
using System.IO;

public class TestAction2
{
   public static void Main()
   {
      string message1 = "The first line of a message.";
      string message2 = "The second line of a message.";
      Action concat;

      if (Environment.GetCommandLineArgs().Length > 1)
         concat = WriteToFile;
      else
         concat = WriteToConsole;

      concat(message1, message2);
   }

   private static void WriteToConsole(string string1, string string2)
   {
      Console.WriteLine("{0}\n{1}", string1, string2);            
   }

   private static void WriteToFile(string string1, string string2)
   {
      StreamWriter writer = null;  
      try
      {
         writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);
         writer.WriteLine("{0}\n{1}", string1, string2);
      }
      catch
      {
         Console.WriteLine("File write operation failed...");
      }
      finally
      {
         if (writer != null) writer.Close();
      }      
   }
}

二、使用delegate定义有返回值的委托:

using System;

delegate string[] ExtractMethod(string stringToManipulate, int maximum);

public class DelegateExample
{
   public static void Main()
   {
      ExtractMethod extractMeth = ExtractWords;
      string title = "The Scarlet Letter";
      foreach (string word in extractMeth(title, 5))
         Console.WriteLine(word);
   }

   private static string[] ExtractWords(string phrase, int limit)
   {
      char[] delimiters = new char[] {' '};
      if (limit > 0)
         return phrase.Split(delimiters, limit);
      else
         return phrase.Split(delimiters);
   }
}

使用泛型Func委托, 则不需要显式定义委托:

using System;

public class GenericFunc
{
   public static void Main()
   {
      Func extractMethod = ExtractWords;
      string title = "The Scarlet Letter";
      foreach (string word in extractMethod(title, 5))
         Console.WriteLine(word);
   }

   private static string[] ExtractWords(string phrase, int limit)
   {
      char[] delimiters = new char[] {' '};
      if (limit > 0)
         return phrase.Split(delimiters, limit);
      else
         return phrase.Split(delimiters);
   }
}

使用Action委托和Func委托,可以简化代码,让逻辑更清晰。

 

Predicate委托

Predicate泛型委托:表示定义一组条件并确定指定对象是否符合这些条件的方法。此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素。

先来看一下Array.FindAll

// 摘要:
//     检索与指定谓词定义的条件匹配的所有元素。
//
// 参数:
//   array:
//     要搜索的从零开始的一维 System.Array。
//
//   match:
//     System.Predicate`1,定义要搜索元素的条件。
//
// 类型参数:
//   T:
//     数组元素的类型。
//
// 返回结果:
//     如果找到一个 System.Array,其中所有元素均与指定谓词定义的条件匹配,
//     则为该数组;否则为一个空 System.Array。
//
// 异常:
//   T:System.ArgumentNullException:
//     array 为 null。 - 或 - match 为 null。
public static T[] FindAll(T[] array, Predicate match);

FindAll两个参数第一个就是数组(字符串数组,int数组等等),第二个就是委托Predicate有一个参数。

第一种方式:通过一个lambda表达式传递参数

string[] arrayString = new string[]{"One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"};

string[] arrayResult = Array.FindAll(arrayString, (c) => c.Length > 3);

第二种方式:通过委托进行传递方法的方式

        public void PredicateArrayTest()
        {
            string[] arrayString = new string[]{"One","Two","Three","Four","Fice","Six",
"Seven","Eight","Nine","Ten"};

            string[] arrayResult = Array.FindAll(arrayString, (c) => c.Length > 3);
            string[] arrayResultMethod = Array.FindAll(arrayString, GetString);
        }
        private bool GetString(string item)
        {
            if (item.Length > 3)
            {
                return true;
            }
            return false;
        }

第三种方式:通过匿名代理

string[] arrayResultDelegate = Array.FindAll(arrayString, delegate(string c) { return c.Length > 3; });

对List的实现其实和Array的实现原理几乎完全一样。

你可能感兴趣的:(C#,数据结构与算法)