在C#中写我的第一个DSL,并挂在func< T> &行动 [英] Writing my first DSL in C# and getting hung up on func<T> & Action

查看:194
本文介绍了在C#中写我的第一个DSL,并挂在func< T> &行动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写一个简单的工具在工作中写我的第一个DSL。我使用构建器模式来设置复杂的父对象,但我跑进砖墙,用于构建父对象的子集合。下面是一个示例:

I'm taking a crack at writing my first DSL for a simple tool at work. I'm using the builder pattern to setup the complex parent object but am running into brick walls for building out the child collections of the parent object. Here's a sample:

使用:

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);

关闭示例(我认为这就是他们的名字):

Sample with closure (I think that's what they're called):

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

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

Sample class (without the child PourIn() method as this is what I'm trying to figure out.)

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

所以在我的应用程序工作,我有复杂的对象建立只是罚款,但我不能为我的生活搞清楚如何获得lambda编码为父对象上的子集合。 (在这个例子中它是expresso的镜头(子集合))。

So in my app for work I have the complex object building just fine, but I can't for the life of me figure out how to get the lambda coded for the sub collection on the parent object. (in this example it's the shots (child collection) of expresso).

也许我在这里混淆概念,我不介意直接设置;

Perhaps I'm confusing concepts here and I don't mind being set straight; however, I really like how this reads and would like to figure out how to get this working.

谢谢你,
Sam

Thanks, Sam

推荐答案

好吧,所以我想出了如何使用额外的表达式构建器编写我的DSL。这是我想要我的DSL读取:

Ok, so I figured out how to write my DSL using an additional expression builder. This is how I wanted my DSL to read:

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

这是我的传球测试:

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

这里是我的CoffeeExpressionBuilder DSL类: / p>

And here's my CoffeeExpressionBuilder DSL class(s):

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

欢迎任何建议。

这篇关于在C#中写我的第一个DSL,并挂在func&lt; T&gt; &amp;行动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆