今天看Curator源码时发现其请求ZooKeeper集群时内部封装了重试机制,代码如下:
Stat resultStat = RetryLoop.callWithRetry
(
client.getZookeeperClient(),
new Callable<Stat>()
{
@Override
public Stat call() throws Exception
{
return client.getZooKeeper().setData(path, data, version);
}
}
);
public static<T> T callWithRetry(CuratorZookeeperClient client, Callable<T> 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<T>,即带返回值T的线程这个功能来将失败时要重试的代码段传递到重试函数中进行调用。
因为我要开发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);
});