如何使用 delegates/lambdas/Func<> 摆脱代码重用?
How can I use delegates/lambdas/Func<> to get rid of code reuse?
我有一个 Web 服务,我发现自己在每个方法中都放置了完全相同的 try/catch 块,并且我试图消除该代码重用。
这是一个示例方法(删除了一些代码),您可以在其中看到#1/#2/#3 是核心调用并且非常相似。
[HttpGet]
[Route("GetKeys")]
[Produces(MediaTypeNames.Application.Json)] // "application/json"
public async Task<EntityKeyPage> GetKeys([FromQuery] string company = "", [FromQuery] DocumentPaging documentPaging = null)
{
[...]
try
{
// Sometimes it's this #1
VendTableServiceGetKeysResponse getKeysResponse = await aifClient.getKeysAsync(getKeysRequest);
// Sometimes it's this #2
// VendTableServiceReadResponse readResponse = await aifClient.readAsync(readRequest);
// Sometimes it's this #3
// VendTableServiceFindKeysResponse findKeysResponse = await aifClient.findKeysAsync(findKeysRequest);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return getKeysResponse.EntityKeyPage;
}
这是我尝试使用的通用方法。
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Out> action, In @in)
{
Out @out;
try
{
@out = action(@in);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return @out;
}
我根据阅读写了那个方法,但我不知道如何调用它?看来我通常会传递一个方法名称,但在这种情况下它将是一个对象+方法 (aifClient.getKeysAsync(...)
/aifClient.readAsync(...)
/aifClient.findKeysAsync(...)
)?
如何调用我的方法,或者我做错了吗?
这是我第一次尝试调用它,但它是错误的:
var response = await MakeAIFCall<VendTableServiceGetChangedKeysRequest, VendTableServiceGetChangedKeysResponse>(aifClient.getKeysAsync, getKeysRequest);
变量 @out
和 @in
是由 intellisense 建议的...我不知道为什么 @
符号在那里或它有什么作用。
由于等待您的方法,我们几乎可以安全地假设它们 return 任务(但是还有其他可能性),因此首先您需要将方法签名更改为如下内容:
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Task<Out>> action, In @in)
{
Out @out;
try
{
@out = await action(@in);
}
....
其次,您可以利用 C# 中 closures 的存在,因此您无需提供参数:
private async Task<Out> MakeAIFCall<Out>(Func<Task<Out>> call)
{
Out @out;
try
{
@out = await call();
}
....
}
然后像这样使用它:
await MakeAIFCall(() => aifClient.getKeysAsync(getKeysRequest));
我有一个 Web 服务,我发现自己在每个方法中都放置了完全相同的 try/catch 块,并且我试图消除该代码重用。
这是一个示例方法(删除了一些代码),您可以在其中看到#1/#2/#3 是核心调用并且非常相似。
[HttpGet]
[Route("GetKeys")]
[Produces(MediaTypeNames.Application.Json)] // "application/json"
public async Task<EntityKeyPage> GetKeys([FromQuery] string company = "", [FromQuery] DocumentPaging documentPaging = null)
{
[...]
try
{
// Sometimes it's this #1
VendTableServiceGetKeysResponse getKeysResponse = await aifClient.getKeysAsync(getKeysRequest);
// Sometimes it's this #2
// VendTableServiceReadResponse readResponse = await aifClient.readAsync(readRequest);
// Sometimes it's this #3
// VendTableServiceFindKeysResponse findKeysResponse = await aifClient.findKeysAsync(findKeysRequest);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return getKeysResponse.EntityKeyPage;
}
这是我尝试使用的通用方法。
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Out> action, In @in)
{
Out @out;
try
{
@out = action(@in);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return @out;
}
我根据阅读写了那个方法,但我不知道如何调用它?看来我通常会传递一个方法名称,但在这种情况下它将是一个对象+方法 (aifClient.getKeysAsync(...)
/aifClient.readAsync(...)
/aifClient.findKeysAsync(...)
)?
如何调用我的方法,或者我做错了吗?
这是我第一次尝试调用它,但它是错误的:
var response = await MakeAIFCall<VendTableServiceGetChangedKeysRequest, VendTableServiceGetChangedKeysResponse>(aifClient.getKeysAsync, getKeysRequest);
变量 @out
和 @in
是由 intellisense 建议的...我不知道为什么 @
符号在那里或它有什么作用。
由于等待您的方法,我们几乎可以安全地假设它们 return 任务(但是还有其他可能性),因此首先您需要将方法签名更改为如下内容:
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Task<Out>> action, In @in)
{
Out @out;
try
{
@out = await action(@in);
}
....
其次,您可以利用 C# 中 closures 的存在,因此您无需提供参数:
private async Task<Out> MakeAIFCall<Out>(Func<Task<Out>> call)
{
Out @out;
try
{
@out = await call();
}
....
}
然后像这样使用它:
await MakeAIFCall(() => aifClient.getKeysAsync(getKeysRequest));