2009-11-25 5 views
6

पर लटका हुआ है मैं काम पर एक साधारण उपकरण के लिए अपना पहला डीएसएल लिखने में एक क्रैक ले रहा हूं। मैं जटिल पैरेंट ऑब्जेक्ट को सेट करने के लिए बिल्डर पैटर्न का उपयोग कर रहा हूं लेकिन पैरेंट ऑब्जेक्ट के बच्चे के संग्रह को बनाने के लिए ईंट की दीवारों में दौड़ रहा हूं।सी # में अपना पहला डीएसएल लिखना और func <T> और एक्शन

उपयोग::

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

तो मेरे काम के लिए मेरे पास जटिल वस्तु निर्माण है ठीक है, लेकिन मैं अपने जीवन के लिए यह नहीं समझ सकता कि लैम्बडा को मूल वस्तु पर उप संग्रह के लिए कोड किया गया है। (इस उदाहरण में यह एक्सप्रेसो के शॉट्स (बाल संग्रह) है)।

शायद मैं यहां अवधारणाओं को भ्रमित कर रहा हूं और मुझे सीधे सेट करने की कोई बात नहीं है; हालांकि, मुझे वास्तव में यह पसंद है कि यह कैसे पढ़ता है और यह समझना चाहता है कि यह काम कैसे प्राप्त करें।

धन्यवाद, सैम

+0

मुझे ईमानदार होना है; यह वास्तव में एक डीएसएल, आईएमएचओ का एक भयानक उपयोग है। यह मेरे लिए बहुत मुश्किल से पढ़ता है। लेकिन प्रत्येक के लिए, मुझे लगता है। –

+0

तो आपकी समस्या क्या है? यह सब कोड मालिकाना दिखता है, इसलिए हमारे पास इसका कोई मतलब नहीं है कि इसका कोई मतलब क्या है। उदाहरण के लिए, IncludeApps का पैरामीटर प्रकार क्या है? – tster

+0

क्या आप IncludeApps विधि के लिए हस्ताक्षर पोस्ट कर सकते हैं? –

उत्तर

2

ठीक है, इसलिए मुझे पता चला कि एक अतिरिक्त अभिव्यक्ति निर्माता का उपयोग करके मेरा डीएसएल कैसे लिखना है। यहाँ

[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 डीएसएल वर्ग (रों) बताया गया है::

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

यहाँ मेरी गुजर परीक्षण: यह कैसे मैं अपने डीएसएल चाहता था पढ़ने के लिए है

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

किसी भी और सभी सुझावों स्वागत है।

2

क्या होगा अगर .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 विधि के अंदर आप पंजीकरण का निरीक्षण करेंगे और आवश्यक वस्तुओं को बनायेंगे।

+0

मुझे निश्चित रूप से लगता है कि आप सही दिशा में जा रहे हैं, लेकिन मैं सी # की प्रणाली का उपयोग कर इस समस्या को हल करना चाहता हूं। एक्शन या सिस्टम। बंद करने के लिए फनक ऑब्जेक्ट्स। यह अवधारणा है कि मैं अपने सिर को चारों ओर समझने की कोशिश कर रहा हूं। धन्यवाद। – sam

+2

यह बंद करने का उपयोग करने के लिए एक उपयोगी जगह नहीं है। Lambda अभिव्यक्ति उपयोगी होती है जब आप 'एक्शन' को परिभाषित करना चाहते हैं जो कुछ अज्ञात पैरामीटर के अनुसार घटित होगा। यहां, सबकुछ ज्ञात है, और आप वास्तव में एक क्रिया को परिभाषित नहीं कर रहे हैं। आप बस फोन पर एक ऐप पंजीकृत करना चाहते हैं। – tster

+0

पैराम्स पर अच्छी कॉल। मैं भी यही सोच रहा था। आपने मुझे इसमें हरा दिया। –

1

प्रतिनिधि मार्ग जाने के लिए शायद ऐसा कुछ काम करेगा?

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

यदि आप प्रतिनिधि मार्ग पर सेट नहीं हैं तो शायद पैरा काम करेंगे?

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; 
    } 
} 
संबंधित मुद्दे