2015-05-26 11 views
6

परिवर्तित होने पर संपत्ति सेट करें मेरे पास ऐसे गुण हैं जिनके सेटर्स को बुलाया जाता है, जैसे परिवर्तनों को निकाल दिया जाता है और/या प्रतिपादन क्रियाएं बदलती हैं। मैं एक फ़ंक्शन कैसे डिज़ाइन कर सकता हूं जो केवल संपत्ति को सेट करेगा यदि उसके मूल्य को बदलने की आवश्यकता है?एफ # -

refs के साथ, मैं तो बस कुछ इस तरह करना होगा:

let setIfChanged (oldVal: Ref<'T>) (newVal: 'T) = if newVal <> !oldVal then oldVal := newVal 
let y = ref 0 
setIfChanged y 1 

हालांकि, परिवर्तनशील गुण refs नहीं हैं, और मैं इस तरह के एक बात यह है कि संकलन होगा डिजाइन करने के लिए किसी भी तरह से खोजने के लिए प्रतीत नहीं कर सकते हैं। उदाहरण के लिए,

let setIfChanged oldVal newVal = if newVal <> oldVal then oldVal <- newVal 

बस मुझे बताएगा कि पुराना वैल व्यवहार्य नहीं है।

क्या पुरानी वैल को एनोटेट करने का कोई तरीका है ताकि यह उत्परिवर्तनीय (सेटटेबल) गुणों के लिए हो? या कोई बेहतर तरीका है?

+0

अच्छी तरह से यह एक शर्म की बात है (आमतौर पर आप चाहते हैं कि सेटर कुछ साइड-इफेक्ट्स नहीं होने पर साइड इफेक्ट्स न करें) आप स्रोत को नहीं बदल सकते - व्यक्तिगत रूप से मैं * अपमानजनक * प्रकारों को लपेटने पर विचार करता हूं - टॉमस उत्तर ऐसा करने का एक अच्छा तरीका लगता है * शॉर्टिश * – Carsten

उत्तर

4

आप कर सकते हैं:

let setIfChanged (oldVal: 'a byref) (newVal : 'a) = if newVal <> oldVal then oldVal <- newVal 
let mutable test = 42 
setIfChanged &test 24 

कहा जा रहा है, लक्ष्यों के अपने विवरण दिया, मैं Gjallarhorn देखने की सलाह देते हैं। यह परिवर्तनीय मूल्यों के शीर्ष पर सिग्नलिंग के लिए समर्थन प्रदान करता है, और जब मूल्य बदलता है तो क्या होता है इसके संदर्भ में बेहद लचीला होने के लिए डिज़ाइन किया गया है। इसे अंतर्निहित तंत्र के रूप में उपयोग किया जा सकता है जिस पर आप आसानी से अपने सिग्नल बना सकते हैं जब चीजें बदलती हैं (यदि यह View मॉड्यूल के माध्यम से आपको पहले से ही प्रदान नहीं करती है)।


संपादित करें:

को देखते हुए अपनी टिप्पणी है कि प्रश्न में संपत्ति एक तीसरी पार्टी विधानसभा में निहित है, एक ही विकल्प एफ # में गतिशील सहायता का उपयोग करने op_DynamicAssignment ऑपरेटर (?<-) गतिशील प्रेषण करने के लिए ओवरराइड करने के लिए किया जाएगा विधि के लिए, लेकिन प्रक्रिया में अपनी "अधिसूचना" उठाओ।

को देखते हुए:

let (?<-) source property (value : 'a) = 
    let p = source.GetType().GetProperty(property) 
    let r = p.GetValue(source, null) :?> 'a 
    if (r <> value) then 
     printfn "Changing value" 
     source.GetType().GetProperty(property).SetValue(source, value, null) 

आप someObj?TheProperty <- newVal कॉल कर सकते हैं, और आप "बदलने मूल्य" प्रिंट केवल तभी मूल्य वास्तव में बदल गया है देखेंगे।

आंतरिक रूप से, यह संपत्ति के पुराने मूल्य को प्राप्त करने के लिए प्रतिबिंब का उपयोग करके काम करता है और नया सेट करता है, इसलिए इसमें सर्वोत्तम प्रदर्शन विशेषताओं नहीं हैं, लेकिन जैसा कि आप संपत्ति को बढ़ाने के लिए इसका उपयोग कर रहे हैं, नोटिफिकेशन टाइप करें, यह संभवतः एक समस्या नहीं है।

+0

यह ऑब्जेक्ट प्रॉपर्टी के साथ कैसे काम करेगा? उदाहरण के लिए 'setIfChanged foo.Text "bar" '। इसके अलावा, मेरे पास कक्षाओं और उनके सदस्यों पर नियंत्रण नहीं है, जिन्हें बाहरी सी # लाइब्रेरी में परिभाषित किया गया है। – dannytoone

+1

@ डैनीटोहन आह, जिसे एक क्षेत्र के खिलाफ काम करना होगा। यह किसी संपत्ति के खिलाफ काम नहीं करेगा ... आपको एहसास नहीं हुआ कि आपके पास प्रकारों तक पहुंच नहीं है। –

+1

@ डैनीटोन ने आपको एफ # में "रैप" करने के लिए गतिशील समर्थन का उपयोग करके एक विकल्प दिया है, जिससे आप प्रक्रिया में अपना ऑपरेशन कर सकते हैं। –

5

मुझे नहीं लगता कि यह "मुफ्त में" करने का कोई आसान तरीका है।

let setIfChanged getter setter v = 
    if getter() <> v then setter(v) 

एक को देखते हुए:

एक चाल है कि यह एक बिट आसान बना सकता है कि आप वास्तव में गेटर और कार्यों के रूप में संपत्ति के सेटर इलाज कर सकते हैं, तो आप setIfChanged लिख सकते हैं एक समारोह दो कार्य लेने के रूप में है तथ्य यह है कि संकलक आप 01 तक पहुँचने के लिए अनुमति देता है

let a = A() 
setIfChanged a.get_P a.set_P 0 
setIfChanged a.get_P a.set_P 1 

: proeperty P साथ वर्ग A, तो आप इस पैरामीटर के रूप में set_P और get_P का उपयोग कर कॉल कर सकते हैंऔर set_P एक छोटी सी चाल है - इसलिए यह कई लोगों के लिए थोड़ा उलझन में हो सकता है। पूर्णता के लिए, यहाँ है कि मैं परीक्षण के लिए इस्तेमाल किया A की परिभाषा है:

type A() = 
    let mutable p = 0 
    member x.P 
    with get() = p 
    and set(v) = printfn "Setting!"; p <- v 

एक और अधिक परिष्कृत दृष्टिकोण कोटेशन और प्रतिबिंब है, जो धीमी हो जाएगा उपयोग करने के लिए होगा, लेकिन यह आप setIfChanged <@ a.P @> 42 की तरह कुछ लिखने करते हैं।