首页 > 解决方案 > 用脚本语言实现简洁的 IF 条件

问题描述

我有一个生成脚本的小助手类,稍后在我的代码中使用,即:

public class ScriptBuilder
{
    public string Script { get; set; }
    public ScriptBuilder NewLine(uint numberOfLines = 1)
    {
        if (numberOfLines == 0)
        {
            return this;
        }
        else
        {
            for (int i = 1; i <= numberOfLines; ++i)
            {
                Script += Environment.NewLine;
            }
            return this;
        }
    }
    public ScriptBuilder WriteLine(string str = "")
    {
        if (str != "")
        {
            Script += str;
            NewLine();
        }
        return this;
    }
    public ScriptBuilder(string line = "")
    {
        Script = line;
        if (line != "")
        {
            NewLine();
        }
    }
    public ScriptBuilder setLong(string longName, long x)
    {
        WriteLine("int " + longName + " " + x.ToString(System.Globalization.CultureInfo.InvariantCulture));
        return this;
    }

    // + other set functions with different parameters/numbers of parameters
}

// ScriptBuilder is used like this :

ScriptBuilder scriptStringBuilder = new ScriptBuilder();
scriptStringBuilder
    .WriteLine($"/!HEADSTART")
    .WriteLine($"/! TYPE = {scriptType}")
    .WriteLine($"/! NAME = {name}")
    .WriteLine($"/! DESCRIPTION  = {description}")
    .WriteLine($"/!HEADEND")
    /* the header is done now */
    .NewLine(2);

这是非常基本的方法链接。我想用这种脚本语言来实现IFIF ELSE IF ELSE,但我没有看到一种非常简洁的方法。

对于IF我想出了成员函数:

public ScriptBuilder IF(bool condition, ScriptBuilder res)
{
    if (condition)
    {
        return res;
    }
    else
    {
        return this;
    }
}

可以用作:

ScriptBuilder.IF(condition,
    scriptStringBuilder
        .setThis(...)
        .setThat(...)
    ;
    )

但我不满意,因为

也许我可以使用代表,例如:

public delegate ScriptBuilder ScriptBuilderFunction(params object[] Parameters);
public ScriptBuilder IF(bool condition, ScriptBuilderFunction func)
{
    // ...
}

但我什至不知道如何实现...

理想情况下,我想写:

scriptStringBuilder.
    .setThis(...)
    .setThat(...)
    .IF(condition)
    .THEN()
        .setThis(...)
        .doThat(...)
    .ELSEIF(othercondition)
        .makeThis(...)
        .doThat(...)
    .ENDIF()
    .setThatNow(...)
    ;

标签: c#method-chainingscripting-language

解决方案


这是您如何实现此功能的非常粗略的草图:

class Program
{
    static void Main(string[] args)
    {
        var number = 999;

        ScriptBuilder scriptStringBuilder = new ScriptBuilder();
        var text = scriptStringBuilder
            .WriteLine($"/!HEADSTART")
            .WriteLine($"/! TYPE = abc")
            .WriteLine($"/! NAME = name")
            .WriteLine($"/!HEADEND")
            .NewLine(2)
            .IfCondition(number != 999, ifCondition => {
                ifCondition.NewLine(1);
                ifCondition.WriteLine("SUCCESS");
            }, elseCondition => {
                elseCondition.NewLine(1);
                elseCondition.WriteLine("FAIL");
            }, 
            elseIf1 => elseIf1.ElseIfCondition(number > 1, h1 => h1.WriteLine("NUMBER IS BIGGER THAN 1")),
            elseIf2 => elseIf2.ElseIfCondition(number > 2, h2 => h2.WriteLine("NUMBER IS BIGGER THAN 2")))
            .Build();

        Console.WriteLine(text);

        Console.ReadKey();
    }
}

public class ScriptBuilder : IElseIfConditionable
{
    private string _script;

    public ScriptBuilder NewLine(uint numberOfLines = 1)
    {
        if (numberOfLines == 0)
        {
            return this;
        }
        else
        {
            for (int i = 1; i <= numberOfLines; ++i)
            {
                _script += Environment.NewLine;
            }
            return this;
        }
    }
    public ScriptBuilder WriteLine(string str = "")
    {
        if (str != "")
        {
            _script += str;
            NewLine();
        }
        return this;
    }
    public ScriptBuilder(string line = "")
    {
        _script = line;
        if (line != "")
        {
            NewLine();
        }
    }
    public ScriptBuilder SetLong(string longName, long x)
    {
        WriteLine("int " + longName + " " + x.ToString(System.Globalization.CultureInfo.InvariantCulture));
        return this;
    }

    public string Build()
    {
        return _script;
    }

    public ScriptBuilder IfCondition(bool condition, Action<ScriptBuilder> trueCondition, Action<ScriptBuilder> falseCondition, params Func<IElseIfConditionable, Tuple<ScriptBuilder, bool>>[] elseIfs)
    {
        if (condition)
        {
            trueCondition(this);
            return this;
        }

        foreach (var elseIf in elseIfs)
        {
            if (elseIf(this).Item2)
            {
                return this;
            }
        }

        if (!condition)
        {
            falseCondition(this);
        }

        return this;
    }

    public Tuple<ScriptBuilder, bool> ElseIfCondition(bool condition, Action<ScriptBuilder> trueCondition)
    {
        if (condition)
        {
            trueCondition(this);
        }

        return Tuple.Create(this, condition);
    }
}

public interface IElseIfConditionable
{
    Tuple<ScriptBuilder, bool> ElseIfCondition(bool condition, Action<ScriptBuilder> trueCondition);
}

这相当于:

var s = new ScriptBuilder();
if (number != 999)
{
    s.NewLine(1);
    s.WriteLine("SUCCESS");
}
else if (number > 1)
{
    s.WriteLine("NUMBER IS BIGGER THAN 1");
}
else if (number > 2)
{
    s.WriteLine("NUMBER IS BIGGER THAN 2");
}
else
{
     s.NewLine(1);
     s.WriteLine("FAIL");
}

推荐阅读