2012-07-27 24 views
21

नमूना कार्यक्रम के लिए के रूप में अशक्त नहीं है:प्रकार एक उचित मूल्य

type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 

let classFactory() = MyClass("up to you") 
let live() = 
    let instance = classFactory() 
    if instance = null then raise(System.Exception("null is not living... that's why OO languages die from bugs")) 
    instance 

मैं त्रुटि मिलती है "प्रकार 'MyClass' एक उचित मूल्य के रूप में अशक्त नहीं है" जब मैं इस वर्ग का उपयोग करने के लिए जाना निहित रूप से टाइप किए गए कार्यों के वापसी मूल्य के रूप में और इसकी तुलना शून्य (सी # निर्भरता इंजेक्शन के साथ संगतता आवश्यकताओं के बी/सी की तुलना में मैं एफ # विकल्प प्रकारों पर भरोसा नहीं कर सकता)।

मैं आसानी से करने के लिए अशक्त जांच बदलकर इसे ठीक कर सकते हैं:

if instance :> obj = null then 

हालांकि, मैं ("लगता है") यह पूरी तरह से "गलत" है। विशेष रूप से जब मैं मानता हूं कि MyClass एक संदर्भ प्रकार है जिसे बॉक्स करने की आवश्यकता नहीं है (सी # पृष्ठभूमि से बोलना)।

मैंने "एफ # वैल्यू प्रतिबंध" के बारे में पढ़ा है और यह किस तरह के अनुमान को प्रभावित करता है, लेकिन मुझे लगता है कि यह इस परिदृश्य पर कैसे लागू होता है।

प्रश्न: क्या ऐसा करने का कोई और तरीका है?

एक तरफ # 1: मैं त्रुटि हो रही है की एक सरल तरीका ...

type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 
let nullMyClass : MyClass = null 

एक तरफ # 2 पाया: मैं बिना सोचे System.Nullable का प्रयास किया ... MyClass एक है संदर्भ प्रकार और एक मान प्रकार (संरचना) नहीं है जो Nullable < _> आवश्यक है। तो, बस मुझे आश्वस्त करता है कि मैं वास्तव में संदर्भ प्रकार से निपट रहा हूं और मुझे आश्चर्यचकित करता है कि एक ऑब्जेक्ट कास्ट अचानक क्यों काम करता है।

अपडेट: किसी भी दिलचस्पी के लिए, मैंने इसे सामान्य सेवा लोकेटर के लिए नीचे दिए गए तीन कार्यों के साथ एक समाधान के रूप में उपयोग किया।

let private getServiceLocator() = 
    try Some(Microsoft.Practices.ServiceLocation.ServiceLocator.Current) 
    with | _ -> None 

let private getService serviceFactory = 
    let serviceLocator = getServiceLocator() 
    let service = match serviceLocator with 
        | None -> serviceFactory() 
        | _ -> 
        match serviceLocator.Value.GetInstance<'a>() with 
        | null -> serviceFactory() 
        | svc -> svc 
    match service with 
    | null -> None 
    | _ -> Some(service) 

let private getRequiredService serviceFactory = 
    let service = getService serviceFactory 
    match service with 
    | None -> raise(MissingServiceException("")) 
    | _ -> service.Value 

उत्तर

39

उपयोग [<AllowNullLiteral>] विशेषता:

[<AllowNullLiteral>] 
type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 

डिफ़ॉल्ट रूप से, एफ # प्रकार प्रत्येक सेवा के लिए अनुरोध इसलिए यदि सेवा वर्ग एफ # में परिभाषित किया गया है, अशक्त का समर्थन करना चाहिए, आप [<AllowNullLiteral>] जोड़ने की जरूरत शून्य की अनुमति न दें (स्वर्ग धन्यवाद!)। यह विशेषता अन्य .NET भाषाओं के साथ इंटरऑप के लिए उपयोगी है और शून्य/असाइनमेंट के साथ तुलना की अनुमति देता है।

+0

दोह! इसे देखने के बाद, मैंने इसे एमएसडीएन "नल वैल्यूज़ (एफ #)" पर तीसरे वाक्य से मान्यता दी: http://msdn.microsoft.com/en-us/library/dd233197(v=vs.110).aspx –

+2

बस जोड़ें - यदि आप इंटरऑप –

+0

जॉन नहीं करते हैं तो यह 'विकल्प' टी का उपयोग करने के लिए अधिक मूर्खतापूर्ण है - हाँ, मैंने विकल्प का उपयोग करने में सक्षम नहीं होने का उल्लेख किया है। तो, सी # के संपर्क में आने वाले प्रत्येक वर्ग को सी # देव के रूप में काम करने के लिए '[] 'की आवश्यकता होगी ... :( –

14

AllowNullLiteral विशेषता के साथ समस्या यह आप शून्य पर अपनी वस्तुओं की तुलना करने के लिए अनुमति देने के अलावा, यह भी है कि बनाता है यह संभव करने के लिए अपने वस्तुओं सेट अशक्त है।

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null) 

फिर बल्कि if instance = null then कर की तुलना में, if isNull instance then बजाय कार्य करें:

यह मानते हुए कि यह आपके उपयोग-मामले के लिए वांछनीय नहीं है, वहाँ सर्वनाश प्रदर्शन प्रभाव के साथ एक आसान विकल्प है।

यह किसी भी संदर्भ प्रकार (रिकॉर्ड और डीयू सहित) के लिए काम करेगा, लेकिन एफ # प्रकारों की वस्तुओं को एफ # से शून्य करने की संभावना को पेश नहीं करता है - दोनों दुनिया के सर्वश्रेष्ठ।

+3

मैंने इस दृष्टिकोण का उपयोग एक बार बड़े-बड़े परियोजना पर किया था, लेकिन इसे पछतावा करना समाप्त हो गया। अगर कोई प्रकार शून्य हो सकता है (या तो एफ # या इंटरऑप के कारण) यह सबसे अच्छा है कि यह स्पष्ट है। एक उदाहरण पैटर्न है मेलिंग। बेहतर क्या है, एक नल-चेकिंग सक्रिय पैटर्न या 'शून्य के साथ मिलान मूल्य -> ​​...'? अंत में, ऐसे कामकाजों को हैकी महसूस हुई। इंटरऑप के लिए, बस अपने प्रकारों में '[]' जोड़ें और शून्य को गले लगाओ। – Daniel

+0

@ डैनियल: मुझे आईएम मिलती है प्रेस कि ओपी बस सी # से एफ # प्रकारों का उपयोग करना चाहता है, इसलिए मुझे नहीं पता कि कितना सच्चा इंटरऑप चल रहा है ... – ildjarn

+0

उपरोक्त है नल परिभाषा वाक्यविन्यास त्रुटि उत्पन्न करती है: ''स्पष्ट प्रकार पैरामीटर केवल मॉड्यूल पर उपयोग किए जा सकते हैं या सदस्य bindings'' मैं इस बजाय की कोशिश की: '' जाने IsNull (एक्स: obj) = obj.ReferenceEquals (एक्स, Unchecked.defaultof <_>) '' बेशक, यह किसी भी मूल्य पैरामीटर स्वचालित रूप से बाध्यकारी के बाद से स्वीकार करेंगे इसे ऑब्जेक्ट करने के लिए ऊपर-कास्ट करें (परिणामी बॉक्स प्रयास के साथ)। तो गैर संदर्भ मान के लिए संकलक चेतावनी खो गया है। – George

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