用C#写我的第一个DSL,然后挂上func <T>&Action

sam*_*sam 6 c# dsl lambda closures action

我正在努力编写我的第一个DSL用于工作中的简单工具.我正在使用构建器模式来设置复杂的父对象,但是我遇到了砖墙,用于构建父对象的子集合.这是一个示例:

使用:

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);
Run Code Online (Sandbox Code Playgroud)

关闭样本(我认为这就是他们所谓的):

var myMorningCoffee = Coffee.Make.WithCream().PourIn( 
                        x => {
                                x.ShotOfExpresso.AtTemperature(100);
                                x.ShotOfExpresso.AtTemperature(100).OfPremiumType();
                             }
                        ).WithOuncesToServe(16);
Run Code Online (Sandbox Code Playgroud)

示例类(没有子PourIn()方法,因为这是我想要弄清楚的.)

 public class Coffee
 {
   private bool _cream;

   public Coffee Make { get new Coffee(); }
   public Coffee WithCream()
   {
     _cream = true;
     return this;
   }
   public Coffee WithOuncesToServe(int ounces)
   {
     _ounces = ounces;
     return this;
   }
 }
Run Code Online (Sandbox Code Playgroud)

所以在我的应用程序工作中,我有复杂的对象构建很好,但我不能为我的生活弄清楚如何获取父对象上的子集合编码的lambda.(在这个例子中,它是expresso的镜头(儿童收藏)).

也许我在这里混淆概念而且我不介意被直接设置; 但是,我真的很喜欢这个如何阅读,并想知道如何使这个工作.

谢谢,山姆

sam*_*sam 3

好的,我想出了如何使用附加表达式生成器来编写 DSL。这就是我希望 DSL 的读取方式:

var myPreferredCoffeeFromStarbucks =
            Coffee.Make.WithCream().PourIn(
                x =>
                    {
                        x.ShotOfExpresso().AtTemperature(100);
                        x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
                    }
                ).ACupSizeInOunces(16);
Run Code Online (Sandbox Code Playgroud)

这是我通过的测试:

[TestFixture]
public class CoffeeTests
{
    [Test]
    public void Can_Create_A_Caramel_Macchiato()
    {
        var myPreferredCoffeeFromStarbucks =
            Coffee.Make.WithCream().PourIn(
                x =>
                    {
                        x.ShotOfExpresso().AtTemperature(100);
                        x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
                    }
                ).ACupSizeInOunces(16);

        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Count == 2);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == true);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == false);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.CupSizeInOunces.Equals(16));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 CoffeeExpressionBuilder DSL 类:

public class Coffee
{
    public List<ExpressoExpressionBuilder> expressoExpressions { get; private set; }

    public bool HasCream { get; private set; }
    public int CupSizeInOunces { get; private set; }

    public static Coffee Make
    {
        get
        {
            var coffee = new Coffee
                             {
                                 expressoExpressions = new List<ExpressoExpressionBuilder>()
                             };

            return coffee;
        }
    }

    public Coffee WithCream()
    {
        HasCream = true;
        return this;
    }

    public Coffee ACupSizeInOunces(int ounces)
    {
        CupSizeInOunces = ounces;

        return this;
    }

    public Coffee PourIn(Action<ExpressoExpressionBuilder> action)
    {
        var expression = new ExpressoExpressionBuilder();
        action.Invoke(expression);
        expressoExpressions.Add(expression);

        return this;
    }

    }

public class ExpressoExpressionBuilder
{
    public readonly Queue<ExpressoExpression> ExpressoShots = 
        new Queue<ExpressoExpression>();

    public ExpressoExpressionBuilder ShotOfExpresso()
    {
        var shot = new ExpressoExpression();
        ExpressoShots.Enqueue(shot);

        return this;
    }

    public ExpressoExpressionBuilder AtTemperature(int temp)
    {
        var recentlyAddedShot = ExpressoShots.Peek();
        recentlyAddedShot.Temperature = temp;

        return this;
    }

    public ExpressoExpressionBuilder OfPremiumType()
    {
        var recentlyAddedShot = ExpressoShots.Peek();
        recentlyAddedShot.IsOfPremiumType = true;

        return this;
    }
}

public class ExpressoExpression
{
    public int Temperature { get; set; }
    public bool IsOfPremiumType { get; set; }

    public ExpressoExpression()
    {
        Temperature = 0;
        IsOfPremiumType = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

欢迎任何和所有建议。