C#函数编程

在 C# 1.0 中,您通过使用在代码中其他位置定义的方法显式初始化委托来创建委托的实例。 C# 2.0 引入了匿名方法的概念,作为一种编写可在委托调用中执行的未命名内联语句块的方式。 C# 3.0 引入了 Lambda 表达式,这种表达式与匿名方法的概念类似,但更具表现力并且更简练。 这两个功能统称为“匿名函数”。 通常,针对 .NET Framework 版本 3.5 及更高版本的应用程序应使用 Lambda 表达式。

下面的示例演示了从 C# 1.0 到 C# 3.0 委托创建过程的发展:

<pre lang="csharp" line="1">class Test
{
   delegate void TestDelegate(string s);
   static void M(string s)
   {
       Console.WriteLine(s);
   }

   static void Main(string[] args)
   {
       // Original delegate syntax required
       // initialization with a named method.
       TestDelegate testDelA = new TestDelegate(M);

       // C# 2.0: A delegate can be initialized with
       // inline code, called an "anonymous method." This
       // method takes a string as an input parameter.
       TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); };

       // C# 3.0. A delegate can be initialized with
       // a lambda expression. The lambda also takes a string
       // as an input parameter (x). The type of x is inferred by the compiler.
       TestDelegate testDelC = (x) => { Console.WriteLine(x); };

       // Invoke the delegates.
       testDelA("Hello. My name is M and I write lines.");
       testDelB("That's nothing. I'm anonymous and ");
       testDelC("I'm a famous author.");

       // Keep console window open in debug mode.
       Console.WriteLine("Press any key to exit.");
       Console.ReadKey();
   }
}
/* Output:
   Hello. My name is M and I write lines.
   That's nothing. I'm anonymous and
   I'm a famous author.
   Press any key to exit.
*/

在上述内容中可以看到,Func是一种具有返回结果的委托,这和Action有些出入。他有什么用呢。。。

在C# 2.0时,微软引入了匿名方法,可以隐式声明一个方法体,而这个方法体是没有名字的,所以用委托来承载它。如下

       private delegate int Add(int a,int b);
       static void Main(string[] args)
       {
           Add add=delegate(int a,int b){return a+b;};
           Console.WriteLine(add(2,3));
           Console.ReadLine();
       }

Func<T,TResult>的出现取代了显示声明委托。

       static void Main(string[] args)
       {
           Func<int,int,int> add=delegate(int a,int b){return a+b;};
           Console.WriteLine(add(2,3));
           Console.ReadLine();
       }

Lambda,MSDN解释如下

所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。 该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。 Lambda 表达式 x => x * x 读作“x goes to x times x”。可以将此表达式分配给委托类型。

Lambda,其实是附于=>左边参数的一种规则,让参数按照何种规则去执行。Lambda表达式既然可以分配给委托类型,这样我们就可以用Lambda表达式代替匿名方法,使代码更简洁易懂了。如下,

       static void Main(string[] args)
       {
           //Func add=delegate(int a,int b){return a+b;};
           Func add = (x, y) => x + y;
           Console.WriteLine(add(2,3));
           Console.ReadLine();
       }

举个例子,去超市买东西结账,用现金不打折,用信用卡打85折扣,用储蓄卡打9折。为防止以后更改,将逻辑部分抽离出来单独处理。如下

   //支付方式
   enum PaymentEnum
   {
       Cash,
       CreditCard,
       SavingsCard
   }

   //支付甬道
   public class PaymentCorridor
   {
       //支付方案
       public static double Payment(PaymentEnum paymentEnum, double theAmount)
       {
           switch (paymentEnum)
           {
               case PaymentEnum.Cash:
                   return theAmount;
               case PaymentEnum.CreditCard:
                   return theAmount * 0.85;
               case PaymentEnum.SavingsCard:
                   return theAmount * 0.9;
               default:
                   return 0;
           }
       }
   }

   public class Program
   {
       private delegate double Pay(PaymentEnum paymentEmum, double theAmount);
       static void Main(string[] args)
       {
           //传统委托
           Pay pay = new Pay(PaymentCorridor.Payment);
           Console.WriteLine(pay(PaymentEnum.Cash, 100.00));

           //不声明委托
           Func pay1 = new Func(PaymentCorridor.Payment);
           Console.WriteLine(pay1(PaymentEnum.CreditCard, 100.00));

           //Lambda求解
           Func pay2 =
               (x, y) => (x == PaymentEnum.Cash ? y :
                   x == PaymentEnum.CreditCard ? y * 0.85 :
                   x == PaymentEnum.SavingsCard ? y * 0.9 : 0);
           Console.WriteLine(pay2(PaymentEnum.SavingsCard, 100.00));

           Console.ReadLine();
       }
   }

若某个物品进行促销,不允许在打折范围内,它是游离在支付规则之外的。由于Func<T,TResult>是一种委托,或许我们这样做会更好一点。

   //支付方式
   public enum PaymentEnum
   {
       Cash,
       CreditCard,
       SavingsCard
   }

   public class Product
   {
       public string ProductID { get; private set; }
       public double TheAmount { get; private set; }
       public Product(string productID, double theAmount)
       {
           this.ProductID = productID;
           this.TheAmount = theAmount;
       }
   }

   //支付甬道
   public class PaymentCorridor
   {
       //支付方案
       public static double Payment(
           PaymentEnum paymentEnum,
           double theTotalAmount,
           List promotionalProducts,
           Func paymentRules)

       {
           double promotionalAmount = promotionalProducts.Sum(p => p.TheAmount);
           theTotalAmount -= promotionalAmount;
           theTotalAmount = paymentRules(paymentEnum,theTotalAmount);
           theTotalAmount += promotionalAmount;
           return theTotalAmount;
       }
   }

   public class Program
   {
       private delegate double Pay(PaymentEnum paymentEmum, double theAmount);
       static void Main(string[] args)
       {
           //促销的商品
           List productList = new List();
           productList.Add(new Product("9527",12.10));
           Console.WriteLine(
               PaymentCorridor.Payment(PaymentEnum.CreditCard,
                                       100.00,
                                       productList,
                                       (x,y) => (x == PaymentEnum.Cash ? y :
                                       x == PaymentEnum.CreditCard ? y * 0.85 :
                                       x == PaymentEnum.SavingsCard ? y * 0.9 : 0)));
           Console.ReadLine();
       }
   }

既,将打折规则以函数(匿名)的形式交给处理对象,处理对象根据该规则处理折扣信息。