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

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

使用:

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

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

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

示例类(没有子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; } } 

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

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

谢谢,山姆

如果.IncludeApps接受了一组AppRegistrations,该怎么办?

 IncludeApps(params IAppRegistration[] apps) 

然后

 public static class App { public static IAppRegistration IncludeAppFor(AppType type) { return new AppRegistration(type); } } public class AppRegistration { private AppType _type; private bool _cost; public AppRegistration(AppType type) { _type = type; } public AppRegistration AtNoCost() { _cost = 0; return this; } } 

所以最终看起来像这样……

 .IncludeApps ( App.IncludeAppFor(AppType.Any), App.IncludeAppFor(AppType.Any).AtNoCost() ) 

在IncludeApps方法中,您将检查注册并根据需要创建对象。

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

 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类:

 public class Coffee { public List 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() }; return coffee; } } public Coffee WithCream() { HasCream = true; return this; } public Coffee ACupSizeInOunces(int ounces) { CupSizeInOunces = ounces; return this; } public Coffee PourIn(Action action) { var expression = new ExpressoExpressionBuilder(); action.Invoke(expression); expressoExpressions.Add(expression); return this; } } public class ExpressoExpressionBuilder { public readonly Queue ExpressoShots = new Queue(); 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; } } 

欢迎任何和所有建议。

去代表路线可能这样的事情会起作用吗?

 var aPhone = MyPhone.Create; MyPhone.Create.IncludeApps ( x => { x.IncludeAppFor(new object()); } ); class MyPhone { public MyPhone IncludeApps(Action includeCommand) { includeCommand.Invoke(this); return this; } } 

如果你没有设置代理路线,params会工作吗?

 var anotherPhone = MyPhone.Create.IncludeApps( new IncludeAppClass(AppType.Math), new IncludeAppClass(AppType.Entertainment).AtNoCost()); class MyPhone { internal MyPhone IncludeApps(params IncludeAppClass[] includeThese) { if (includeThese == null) { return this; } foreach (var item in includeThese) { this.Apps.Add(Item); } return this; } }