2009-11-25 29 views
6

Tôi đang thực hiện việc viết DSL đầu tiên của mình cho một công cụ đơn giản trong công việc. Tôi đang sử dụng mô hình xây dựng để thiết lập đối tượng cha mẹ phức tạp nhưng đang chạy vào các bức tường gạch để xây dựng bộ sưu tập con của đối tượng cha. Dưới đây là một ví dụ:Viết DSL đầu tiên của tôi trong C# và bị treo lên trên func <T> & Hành động

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

mẫu với đóng cửa (Tôi nghĩ đó là những gì họ đang gọi)::

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

lớp mẫu (không có con PourIn() phương pháp như thế này

Sử dụng

là những gì tôi đang cố gắng tìm ra.)

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

Vì vậy, trong ứng dụng của tôi cho công việc Tôi có xây dựng đối tượng phức tạp tốt, nhưng tôi không thể cho cuộc sống của tôi tìm ra cách để có được mã lambda cho bộ sưu tập phụ trên đối tượng cha mẹ. (trong ví dụ này là các bức ảnh (bộ sưu tập trẻ em) của expresso).

Có lẽ tôi là khái niệm khó hiểu ở đây và tôi không ngại bị đặt thẳng; tuy nhiên, tôi thực sự thích cách đọc này và muốn tìm ra cách để làm việc này.

Cảm ơn, Sam

+0

Tôi phải trung thực; đó thực sự là một sử dụng khủng khiếp của DSL, IMHO. Nó đọc khủng khiếp với tôi. Nhưng với từng người, tôi cho là vậy. –

+0

Vậy vấn đề của bạn là gì? Tất cả các mã này trông độc quyền, vì vậy chúng tôi không thể nào biết được ý nghĩa của nó. Ví dụ, kiểu tham số của IncludeApps là gì? – tster

+0

Bạn có thể đăng chữ ký cho phương thức IncludeApps không? –

Trả lời

2

Ok, vì vậy tôi đã tìm hiểu cách viết DSL bằng trình tạo biểu thức bổ sung. Đây là cách tôi muốn DSL của tôi để đọc:

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

Dưới đây là bài kiểm tra đi qua tôi:

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

Và đây là lớp học của tôi CoffeeExpressionBuilder DSL (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; 
    } 
} 

Bất kỳ và tất cả các gợi ý được hoan nghênh.

2

gì nếu .IncludeApps chấp nhận một loạt các AppRegistrations

IncludeApps(params IAppRegistration[] apps) 

sau đó

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

vậy cuối cùng nó sẽ trông như thế này ...

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

Bên trong phương thức IncludeApps của bạn, bạn sẽ kiểm tra việc đăng ký và tạo các đối tượng theo yêu cầu.

+0

Tôi chắc chắn nghĩ rằng bạn đang đi đúng hướng, nhưng tôi muốn giải quyết vấn đề này bằng cách sử dụng các đối tượng System.Action hoặc System.Func của C# trong một bao đóng. Đây là khái niệm mà tôi đang cố nắm lấy đầu tôi. Cảm ơn. – sam

+2

Đây không phải là nơi hữu ích để sử dụng đóng. Các biểu thức lambda rất hữu ích khi bạn muốn xác định một 'hành động' sẽ xảy ra theo một số tham số không xác định. Ở đây, tất cả mọi thứ được biết đến, và bạn không thực sự xác định một hành động. Bạn chỉ muốn đăng ký một ứng dụng trên điện thoại. – tster

+0

Cuộc gọi tốt trên các thông số. Tôi đã nghĩ giống như vậy. Bạn đánh bại tôi vào nó. –

1

Để đi tuyến đường đại biểu có thể một cái gì đó như thế này sẽ làm việc?

var aPhone = MyPhone.Create; 
    MyPhone.Create.IncludeApps 
    (
    x => 
     { 
     x.IncludeAppFor(new object()); 
     } 
); 

class MyPhone 
    { 
    public MyPhone IncludeApps(Action<MyPhone> includeCommand) 
    { 
     includeCommand.Invoke(this); 
     return this; 
    } 
    } 

Nếu bạn không đặt trên tuyến đường đại biểu, các tham số có thể hoạt động?

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; 
    } 
} 
Các vấn đề liên quan