今天看Curator源码时发现其请求ZooKeeper集群时内部封装了重试机制,代码如下:
Stat resultStat = RetryLoop.callWithRetry
(
client.getZookeeperClient(),
new Callable()
{
@Override
public Stat call() throws Exception
{
return client.getZooKeeper().setData(path, data, version);
}
}
);
public static T callWithRetry(CuratorZookeeperClient client, Callable proc) throws Exception
{
T result = null;
RetryLoop retryLoop = client.newRetryLoop();
while ( retryLoop.shouldContinue() )
{
try
{
client.internalBlockUntilConnectedOrTimedOut();
//调用带返回值的Callable方法
result = proc.call();
retryLoop.markComplete();
}
catch ( Exception e )
{
retryLoop.takeException(e);
}
}
return result;
}
利用Java中的Callable因为我要开发C#的对应的版本,所以也需要将一段代码(请求ZooKeeper的代码)传递到这样一个具备失败重试功能的函数中运行,由于我对C#不是很熟悉,所以能想到的只有通过声明一个代理,再定义一个操作ZooKeeper的函数,将这个函数赋值给代理,将代理传递到具备重试功能的函数中。
但是这种方式势必要定义一个代理,还要显式申明一个方法赋值给代理,代码量大且不是很优雅,所以我就开始深入了解C#这方面如何实现,然后发现了C#2.0引入的匿名方法,以及C#3.0引入的用于取代匿名方法的Lambda表达式,是编写内联代码的首选。下面先提供我写的一段测试代码,可以完成我的需求,之后再讲解何谓匿名方法和Lambda表达式。
CustomDelegate.cs:
using System;
using System.Collections.Generic;
using System.Linq;
namespace DelegateAndLamda
{
delegate string CustomDelegate(string material);
}
PizzaMaker.cs:
namespace DelegateAndLamda
{
class PizzaMaker
{
public static void makePizza(string material, CustomDelegate bake)
{
//前面有一堆固定流程,但是接下来烘烤方法不同
string result = bake(material);
Console.WriteLine(result);
}
}
}
Program.cs
namespace DelegateAndLamda
{
class Program
{
public static void Main(string[] args)
{
//在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法
CustomDelegate bake = new CustomDelegate(bakePizza);
PizzaMaker.makePizza("张三的Pizza", bake);
// C# 2.0 引入了匿名方法
PizzaMaker.makePizza("李四的Pizza", delegate(string material)
{
return String.Format("将{0}烘烤成面包", material);
} );
//在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式
PizzaMaker.makePizza("季义钦的Pizza", material =>
{
return String.Format("将{0}烘烤成意大利pizza", material);
});
}
public static string bakePizza(string material)
{
return String.Format("将{0}烘烤成西瓜", material);
}
}
}
Lambda表达式
Lambda表达式是一种可用于创建委托或表达式目录树类型的匿名函数。 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。 Lambda 表达式对于编写 LINQ 查询表达式特别有用。
若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。 例如,lambda表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值。
1 表达式 lambda
表达式位于 => 运算符右侧的 lambda 表达式称为“表达式 lambda”。 表达式 lambda 广泛用于表达式树(C#和 Visual Basic)的构造。 表达式 lambda 会返回表达式的结果,并采用以下基本形式:
(input parameters) => expression
2语句lambda
语句 lambda 与表达式 lambda 表达式类似,只是语句括在大括号中:
(input parameters) => {statement;}
C#内置委托
其实细心的朋友会发现,即使是使用lambda表达式定义一段代码作为参数进行传递,虽然不需要显式定义一个函数了,但是仍然要自定义一个委托,那么C#中是否有一些内置的委托可以满足我们的需求呢?即我们不需要再去定义一些委托,尽量减少代码量,答案是肯定的。
内置的委托就像我们自己已定义好的一样,要实现某些功能,我们可以直接利用系统内置委托,实例化它们,而不必显式定义一个新委托并将命名方法分配给该委托。
一、Action类的委托
1.Action委托 封装一个方法,该方法不具有参数并且不返回值
2.Action
3.Action
…… ……
17.Action
下面以Action
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
static void Main(string[] args) { #region Action //需求:打印出整型集合list的元素 List //将匿名方法分配给 Action Action list.ForEach(concat1); //将 lambda 表达式分配给 Action Action list.ForEach(concat2); Console.ReadKey(); #endregion } |
总结:
Action类的委托最少可以传入0个参数,最多可以传入16个参数,参数类型皆为逆变,并且不返回值。
二、Func类的委托
1.Func(TResult)委托封装封装一个不具有参数但却返回 TResult 参数指定的类型值的方法
2.Func(T,TResult)委托 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法
3.Func(T1,T2,TResult)委托 封装一个具有两个参数并返回 TResult 参数指定的类型值的方法
…… ……
17.Func
下面以Func
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { #region Func //需求:查找整型集合list中大于3的所有元素组成的新集合,并打印出集合元素 List //将匿名方法分配给 Func Func var newlist1 = list.Where(concat1).ToList(); //将 Lambda 表达式分配给 Func Func var newlist2 = list.Where(concat2).ToList(); newlist1.ForEach(i => Console.WriteLine(i.ToString())); newlist2.ForEach(i => Console.WriteLine(i.ToString())); Console.ReadKey(); #endregion } |
总结:
Func类的委托最少可以传入输入泛型参数(in,逆变) 1个,最多可以传入输入泛型参数(in,逆变) 16个,传入的输出泛型参数(out,协变)有且只有一个,这个类型是此委托封装的方法的返回值类型。
三、Predicate
表示定义一组条件并确定指定对象是否符合这些条件的方法
下面给出Predicate
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { #region Predicate //需求:查找整型集合list中大于3的所有元素组成的新集合,并打印出集合元素 List //将匿名方法分配给 Predicate Predicate var newlist1 = list.FindAll(concat1); //将 lambda 表达式分配给 Predicate Predicate var newlist2 = list.FindAll(concat2); newlist1.ForEach(i => Console.WriteLine(i)); newlist2.ForEach(i => Console.WriteLine(i)); Console.ReadKey(); #endregion } |
总结:
Predicate
四、Comparison
表示比较同一类型的两个对象的方法
下面给出Comparison
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { #region Comparison //需求:将整型集合list中的所有元素倒序排列打印出来 List //将匿名方法分配给 Comparison Comparison //将 lambda 表达式分配给 Comparison Comparison list.Sort(concat1); list.ForEach(c => Console.WriteLine(c.ToString())); list.Sort(concat2); list.ForEach(c => Console.WriteLine(c.ToString())); Console.ReadKey(); #endregion } |
总结:
Comparison
值 |
含义 |
小于0 |
x 小于y |
0 |
x 等于y |
大于0 |
x 大于y |
委托: http://msdn.microsoft.com/zh-cn/library/900fyy8e.aspx
匿名方法: http://msdn.microsoft.com/zh-cn/library/0yw3tz5k.aspx
Lambda表达式: http://msdn.microsoft.com/zh-cn/library/bb397687.aspx
表达式树: http://msdn.microsoft.com/zh-cn/library/bb397951.aspx
Linq查询: http://msdn.microsoft.com/zh-cn/library/bb397906.aspx