【问题标题】:Remove nested if statements [closed]删除嵌套的 if 语句 [关闭]
【发布时间】:2016-03-23 12:21:58
【问题描述】:

嗨,我正在写project,而我现在正在做的部分正在快速膨胀。如何删除这个嵌套的 if 语句,但仍然具有相同的行为?

如果生成的代码简洁,并且不需要额外的本地标志,那就太好了。下面的代码现在可能看起来不那么糟糕了,但是我正计划编写更多方法,直到 T16,你可以想象这些嵌套的 if 语句会变得多么糟糕。

using ContainerExpressions.Containers;
using System;

namespace ContainerExpressions.Expressions.Core
{
    internal static class Compose
    {
        public static Response<T> Evaluate<T>(Func<Response<T>> func) => func();

        public static Response<TResult> Evaluate<T1, TResult>(Func<Response<T1>> func1, Func<T1, Response<TResult>> funcResult)
        {
            var response = new Response<TResult>();

            var result = func1();
            if (result)
            {
                response = response.WithValue(funcResult(result));
            }

            return response;
        }

        public static Response<TResult> Evaluate<T1, T2, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<TResult>> funcResult)
        {
            var response = new Response<TResult>();

            var result1 = func1();
            if (result1)
            {
                var result2 = func2(result1);
                if (result2)
                {
                    response = response.WithValue(funcResult(result2));
                }
            }

            return response;
        }

        public static Response<TResult> Evaluate<T1, T2, T3, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<T3>> func3, Func<T3, Response<TResult>> funcResult)
        {
            var response = new Response<TResult>();

            var result1 = func1();
            if (result1)
            {
                var result2 = func2(result1);
                if (result2)
                {
                    var result3 = func3(result2);
                    if (result3)
                    {
                        response = response.WithValue(funcResult(result3));
                    }
                }
            }

            return response;
        }
    }
}

我最终创建的代码

根据我在这里恢复的建议,我得到了代码膨胀,现在看起来如下:

using ContainerExpressions.Containers;
using System;
using System.Runtime.CompilerServices;

namespace ContainerExpressions.Expressions.Core
{
    internal static class Compose
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Response<TResult> Evaluate<T1, TResult>(Func<Response<T1>> func1, Func<T1, Response<TResult>> funcResult)
        {
            var result = func1();
            return result ? funcResult(result) : Response.Create<TResult>();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Response<TResult> Evaluate<T1, T2, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<TResult>> funcResult)
        {
            var result = func1();
            return result ? Evaluate(() => func2(result), funcResult) : Response.Create<TResult>();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Response<TResult> Evaluate<T1, T2, T3, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<T3>> func3, Func<T3, Response<TResult>> funcResult)
        {
            var result = func1();
            return result ? Evaluate(() => func2(result), func3, funcResult) : Response.Create<TResult>();
        }
    }
}

【问题讨论】:

标签: c#


【解决方案1】:

像这样重用其他方法怎么样:

internal static class Compose
{
    public static Response<T> Evaluate<T>(Func<Response<T>> func) => func();

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Response<TResult> Evaluate<T1, TResult>(Func<Response<T1>> func1, Func<T1, Response<TResult>> funcResult)
    {
        var response = new Response<TResult>();

        var result = func1();
        if (result)
        {
            response = response.WithValue(funcResult(result));
        }

        return response;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Response<TResult> Evaluate<T1, T2, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<TResult>> funcResult)
    {
        return func1() ? Evaluate(func2, funcResult) : new Response<TResult>();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Response<TResult> Evaluate<T1, T2, T3, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<T3>> func3, Func<T3, Response<TResult>> funcResult)
    {
        return func1() ? Evaluate(func2, func3, funcResult) : new Response<TResult>();
    }
}

【讨论】:

  • 嘿西蒙,我想过,它满足了我所有的语法梦想,但我担心这种方法的额外函数调用。例如,如果您要在哪里组合 16 个函数,则需要进行 16 个额外的函数调用(因为每个 Evaluate 都会调用比它小的那个)。
  • 如果这是一个问题,您可以只内联方法,这将消除性能方面。
  • 这可以使用[MethodImpl(MethodImplOptions.AggressiveInlining)] 属性来完成,但是如果它看起来合适,JIT 编译器可能会决定内联您的方法。
  • 谢谢我以前没用过,但听起来不错。我会试一试。
  • 那么该属性是否位于该 compose 类中的每个方法之上?
【解决方案2】:

如果您的代码将始终按照所示部分运行,您可以将其重构为提前返回。我以你的Evaluate&lt;T1, T2, T3, TResult&gt;(...) 为例:

public static Response<TResult> Evaluate<T1, T2, T3, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<T3>> func3, Func<T3, Response<TResult>> funcResult)
{
    var response = new Response<TResult>();

    if (!func1()) return response;
    if (!func2(true)) return response;
    if (!func3(true)) return response;
    return response.WithValue(funcResult(true));
}

所以你摆脱了嵌套的if 语句。而且您不需要本地标志变量,因为您知道值为true


结合 Simon Karlsson 的回答,您的代码可能如下所示:

public static Response<T> Evaluate<T>(Func<Response<T>> func) => func();

public static Response<TResult> Evaluate<T1, TResult>(Func<Response<T1>> func1, Func<T1, Response<TResult>> funcResult)
{
    var response = new Response<TResult>();
    return func1() ? response.WithValue(funcResult(result)) : response;
}

public static Response<TResult> Evaluate<T1, T2, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<TResult>> funcResult)
{
    var response = new Response<TResult>();
    return func1() ? Evaluate(func2, funcResult) ? : response;
}

public static Response<TResult> Evaluate<T1, T2, T3, TResult>(Func<Response<T1>> func1, Func<T1, Response<T2>> func2, Func<T2, Response<T3>> func3, Func<T3, Response<TResult>> funcResult)
{
    var response = new Response<TResult>();
    return func1() ? Evaluate(func2, func3, funcResult) : response;
}

【讨论】:

  • 虽然我很欣赏您来自哪里,但您在此处显示的代码与我的示例不同。 func 的结果不是布尔值。它们是一种可以隐式转换为任何 T 的类型,也可以转换为 boo.
  • 除了第一个之外,还可以像 return func1() ? Evaluate(func2, funcResult) : new Response&lt;TResult&gt;(); 这样更清楚地声明!
  • 哦,没有认识到那个重要的部分;)但是您显示的代码根本无法编译?因为if (result) 只有在resultbool 时才会编译。
  • @RenéVogt 它确实编译了see here,我喜欢你和西蒙的答案的结合,我将两种方法合二为一。
  • @user1515024 啊好吧,看来我今天工作太久了,没有考虑演员表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
相关资源
最近更新 更多