2016-01-15 3 views
10

मैं कार्यों के पारित होने वाले अवैध मानकों के खिलाफ सुरक्षा के लिए एक सरल गार्ड एपीआई का निर्माण कर रहा हूं।फ्लुएंट नेस्टेड गार्ड एपीआई कैसे बनाएं

public static class Guard 
{ 
    public static GuardArgument<T> Ensure<T>(T value, string argumentName) 
    { 
     return new GuardArgument<T>(value, argumentName); 
    } 
} 

public class GuardArgument<T> 
{ 
    public GuardArgument(T value, string argumentName) 
    { 
     Value = value; 
     Name = Name; 
    } 

    public T Value { get; private set; } 
    public string Name { get; private set; } 
} 

// Example extension for validity checks 
public static GuardArgument<T> IsNotNull<T>(this GuardArgument<T> guardArgument, string errorMessage) 
{ 
    if (guardArgument.Value == null) 
    { 
     throw new ArgumentNullException(guardArgument.Name, errorMessage); 
    } 

    return guardArgument; 
}  

पल कोड करने के लिए एक समान तरीके से इस्तेमाल किया जा सकता (ध्यान दें कि यह सिर्फ एक गूंगा उदाहरण है) पर:

void DummyMethod(int? someObject) { 

    Guard.Ensure(someObject, "someObject") 
     .IsNotNull() 
     .IsGreaterThan(0) 
     .IsLessThan(10); 
} 

यह सब काम करता है

मैं निम्नलिखित कोड है ठीक।

Guard.Ensure(someObject, "someObject") 
    .IsNotNull() 
    .Property(
     (x => x.ChildProp1, "childProp1") 
      .IsNotNull() 
      .IsGreaterThan(10) 
    ) 
    .Property(
     (x => x.ChildProp2, "childProp2") 
      .IsNotNull() 
      .IsLessThan(10) 
    ); 

जाहिर है नए .Property विधि श्रृंखला के लिए माता-पिता GuardArgument वापस जाने के लिए की जरूरत है: क्या मैं अब ऐसा करने में सक्षम होना चाहता हूँ एपीआई का विस्तार निम्नलिखित तरीके से जाँच में बच्चे के गुण शामिल करने के लिए है। इसके अलावा बच्चे संपत्ति मौजूदा जांच के तरीकों (IsNotNull() आदि) का उपयोग करने के लिए कोड दोहराव से बचने के लिए सक्षम होने की जरूरत है।

मैं काम नहीं कर सकता कि लैम्ब्डा/प्रॉपर्टी फ़ंक्शन पैरामीटर कैसे बनाएं या जहां .Property विधि स्थित होनी चाहिए - यानी यह GuardArgument या कहीं और, यानी एपीआई के लिए बेहतर संरचना होने पर भी संपत्ति होनी चाहिए ।

+1

लिखने में कोई त्रुटि है, लेकिन GuardArgument निर्माता सेट 'नाम = Name' –

+1

आप कहते हैं कि," जाहिर है नए '.Property' विधि क्रम में माता-पिता' GuardArgument' वापस जाने के लिए की जरूरत है कतार के लिए।" - नहीं, यह सही नहीं है। यदि आप एक धाराप्रवाह एपीआई बनाने की कोशिश कर रहे हैं तो आप माता-पिता से पारित नहीं करना चाहिए - आप एक नया 'GuardArgument' कि माता-पिता घोंसले अन्यथा आप श्रृंखला के साथ संदर्भ को बनाए रखना और फिर नए चेन का निर्माण करने की कोशिश कर रहा द्वारा भयानक कीड़े बना सकते हैं निर्माण करना चाहिए उनसे। – Enigmativity

उत्तर

7

निम्न फ़ंक्शन आपको जो भी चाहिए, उसके समान वाक्यविन्यास की अनुमति देता है।

public static GuardArgument<T> Property<T, TProp>(this GuardArgument<T> guardArgument, Func<T, TProp> getProperty, string propertyName, Action<GuardArgument<TProp>> validate) 
{ 
    GuardArgument<TProp> propertyGuardArgument = new GuardArgument<TProp>(getProperty(guardArgument.Value), propertyName); 

    validate(propertyGuardArgument); 

    return guardArgument; 
} 

समारोह चयनित प्रॉपर्टी के लिए एक नया GuardArgument बनाता है और फिर Action पैरामीटर में इस गुजरता के रूप में आप चाहते हैं आप मान्य करने के लिए अनुमति देने के लिए।

यह गुणों की अनंत श्रृंखला को भी अनुमति देता है, हालांकि मुझे यकीन नहीं है कि यह विशेष रूप से पठनीय होगा।

उपयोग:

Guard.Ensure(someObject, "someObject") 
    .IsNotNull() 
    .Property(x => x.ChildProp1, "childProp1", childProp1 => 
     childProp1.IsNotNull() 
        .IsLessThan(10) 
        .Property(y => y.InnerChildProperty, "innerChildProperty", innerChildProperty => 
         innerChildProperty.IsNotNull() 
        ) 
    ) 
    .Property(x => x.ChildProp2, "childProp2", childProp2 => 
     childProp2.IsNotNull() 
        .IsGreaterThan(10) 
    ); 
+0

जावास्क्रिप्ट "डूम का पिरामिड" जैसा दिखता है;) – jlvaquero

+0

वैसे भी, याद रखें कि आप इसे फ्लैंट के बाहर पहले फनक और एक्शन बनाने और इसे बनाने के लिए फ़्लैट कर सकते हैं और फिर उन्हें संपत्ति() में भेज सकते हैं। – jlvaquero

0

मुझे लगता है कि आपको मूल ऑब्जेक्ट चेक की श्रृंखला में संपत्ति जांच डालने से कोई लाभ नहीं है। तो मैं एक और श्रृंखला पैरेंट ऑब्जेक्ट के लिए और प्रत्येक प्रॉपर्टी के एक श्रृंखला बनाने के लिए सिफारिश करेंगे। यह बहुत अधिक पठनीय है:

Guard.Ensure(a, "a") 
    .IsNotNull("a is null"); 
    Guard.Ensure(a.p0, "a.p0") 
    .IsGreaterThan(10); 
    Guard.Ensure(a.p1, "a.p1") 
    .IsGreaterThan(5); 
0

मुझे लगता है कि आप यहां एक पहिया को फिर से शुरू कर रहे हैं। इस एक्सटेंशन को इंस्टॉल - Code Contracts और यहाँ है कि यह कैसे उपयोग करने के लिए docs है।

आधारित कोड के अलावा आपके जैसे ही इस बात पर ज़ोर, अर्थात्:

public int[] Bar(){ 
    Contract.Ensures(Contract.ForAll(0, Contract.Result<int[]>().Length, index => Contract.Result<int[]>()[index] > 0)); 

.... 
} 

या

Contract.Requires<ArgumentNullException>(x.Value.NestedObject != null, ”x.Value.NestedObject”); 

लेकिन यह भी गुण और जाँच इंटरफेस, अच्छा पूर्व और पोस्ट के लिए कार्यों की व्यापक सेट है स्थिति आदि अभी देखें!

+2

मैंने एक परियोजना पर कोड अनुबंध का उपयोग किया है और उन्हें उपयोग करने के लिए दर्द पाया है। वे निर्माण की गति को क्रॉल में कम करते हैं। कुछ महीनों के बाद हम उन्हें बाहर ले गए और इसके बजाय सवाल की तरह कुछ के लिए गए। – Sean

+2

धन्यवाद @ सेन, हमने हाल ही में उनका उपयोग करना शुरू कर दिया है, और आपके पास बहुत कुछ नहीं है, इसलिए अभी तक बहुत खराब होने के लिए बिल्ड समय पर ध्यान नहीं दिया है। – vittore

+0

मैंने कोड अनुबंधों और सीन की तरह पहले से ही देखा है, बिल्ड की गति धीमी थी और केवल वास्तव में विधि इनपुट की सुरक्षा के लिए उपयोग किया जा रहा था। इसलिए वजन में बहुत हल्का करने की आवश्यकता .. – Graham

संबंधित मुद्दे