【问题标题】:How can I use delegates/lambdas/Func<> to get rid of code reuse?如何使用 delegates/lambdas/Func<> 摆脱代码重用?
【发布时间】:2021-05-06 21:57:31
【问题描述】:

我有一个 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 是由智能感知建议的...我不知道为什么@ 符号在那里或它的作用。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core generics asp.net-mvc-5


    【解决方案1】:

    由于您的方法正在等待,我们几乎可以安全地假设它们返回任务(但是还有其他可能性),因此首先您需要将您的方法签名更改为如下内容:

    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));
    

    【讨论】:

    • 这太棒了。我将不得不盯着它看一会儿才能弄清楚它是如何工作的,但是谢谢!知道为什么它建议的变量是@out 而不仅仅是out?不过,我可能可以在 Google 上找到它。
    • @WilliamYK 很高兴为您提供帮助!至于@out - inout 在 C# 中是 reserved identifiers@ 用于创建 verbatim identifier,因此您可以使用这些词调用变量/参数。
    • 啊,所以我恰好选择了一个关键字 (Out),所以 @ 防止编译器出错,因为我恰好选择了关键字?
    • @WilliamYK 是的,没错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-24
    相关资源
    最近更新 更多