2010-02-15 17 views
9

मैं सी # प्रतिनिधियों के साथ पूर्ववत कार्यक्षमता को लागू करने की कोशिश कर रहा हूं। असल में, मुझे एक UndoStack मिला है जो प्रत्येक पूर्ववत ऑपरेशन को लागू करने वाले प्रतिनिधियों की एक सूची बनाए रखता है। जब उपयोगकर्ता संपादित करता है: पूर्ववत करें, यह स्टैक पहले प्रतिनिधि को बंद कर देता है और इसे चलाता है। प्रत्येक ऑपरेशन स्टैक पर उचित पूर्ववत प्रतिनिधि को धक्का देने के लिए ज़िम्मेदार है। तो मान लीजिए मेरे पास "SetCashOnHand" नामक एक विधि है। यह इस तरह दिखता है:सी # लैम्बडास: कैसे "नहीं * *" Dereference "को परिभाषित करने के लिए?

public void SetCashOnHand(int x) { 
    int coh = this.cashOnHand; 
    undo u =() => this.setCashOnHand(coh); 
    this.cashOnHand = x; 
    undoStack.Push(u); 
} 

तो इस विधि पूर्ववत प्रतिनिधि निर्माण, संचालन करता है, और (यह मानते हुए यह सफल होता है) UndoStack पर पूर्ववत प्रतिनिधि धकेलती है। (UndoStack इतना स्मार्ट है कि अगर पूर्ववत करने के लिए पूर्ववत करें। पुश को पूर्ववत के संदर्भ में बुलाया जाता है, तो प्रतिनिधि इसके बजाय रेडो स्टैक पर जाता है।)

मेरी समस्या यह है कि यह "कैश" करने के लिए थोड़ा परेशान है। CashOnHand में कोह चर काश मैं सिर्फ इस लिख सकते हैं:

undo u =() => this.setCashOnHand(this.cashOnHand); 

लेकिन निश्चित है कि वर्तमान cashOnHand का मूल्य नहीं मिलेगा; जब तक प्रतिनिधि को बुलाया जाता है तब तक यह मूल्य को देखता है, इसलिए कोड कुछ भी नहीं कर रहा है। क्या कोई तरीका है कि मैं प्रतिनिधि को बनाते समय "dereference" cashOnHand कर सकता हूं, अन्य स्थानीय चर में मूल्य को भरने के अलावा कोह?

मैं पूर्ववत करने के बेहतर तरीकों के बारे में सुनने में वास्तव में रूचि नहीं रखता हूं। प्रतिनिधियों के बारे में एक सामान्य प्रश्न के रूप में इस बारे में सोचें, प्रश्न को और स्पष्ट करने के लिए केवल पूर्ववत उदाहरण के साथ।

+1

मुझे लगता है कि आप _Edit_, पूर्ववत करें। – SLaks

+0

ओह, आप सही हैं। मैंने सवाल तय कर लिया है। –

उत्तर

6

आम तौर पर, आप जो भी कर रहे हैं उससे अलग के लिए कोई सही समाधान नहीं है।

हालांकि, अपने विशिष्ट मामले में, आप एक currier कर सकते हैं, इस तरह: अपने विधि अन्य पैरामीटर लेता

Curry(setCashOnHand, this.cashOnHand); 

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

static Action Curry(Action<T> method, T param) { return() => method(param); } 

आप इस तरह उपयोग कर सकते हैं इसका उपयोग इस प्रकार करें:

Curry(cashOnHand => setCashOnHand(3, cashOnHand), this.cashOnHand); 
+1

यह सबसे अच्छा विकल्प लगता है। लेकिन यह इतना भ्रमित है, मुझे लगता है कि मैं मूल्य को स्थानीय चर में कॉपी करने के साथ ही रहूंगा। –

+0

शुद्धता बनाम रखरखाव। =) –

2

नहीं, यदि आप उस विशेष समय पर मूल्यांकन करना चाहते हैं तो आपको लैम्बडा के बाहर अपने आवृत्ति चर के मूल्य को कैप्चर करना होगा।

यह कोई अलग है अगर आप की तुलना में लिखा था इस:

public void SetCashOnHand(int x) { 
    this.cashOnHand = x; 
    undoStack.Push(UndoSetCashOnHand); 
} 

private void UndoSetCashOnHand() 
{ 
    this.setCashOnHand(this.cashOnHand); 
} 

लैम्ब्डा वाक्यविन्यास अभी के बाद से मूल्यांकन प्रकट होता है घोषित विधि शरीर का एक हिस्सा बनने के लिए यह थोड़ा भ्रमित करते हैं, जब वास्तविकता में यह है स्वचालित रूप से जेनरेट किए गए निजी फ़ंक्शन का हिस्सा जो किसी भी अन्य फ़ंक्शन की तरह मूल्यांकन किया जाता है।

लोग आम तौर पर इसके आसपास कैसे जाते हैं, पैरामीटरयुक्त फ़ंक्शन का उपयोग करके और स्टैक के हिस्से के रूप में कार्य को पारित करने वाले मान को संग्रहीत करना है। यदि, हालांकि, आप पैरामीटर- कम फ़ंक्शन के साथ जाना चाहते हैं, तो आपको इसे स्थानीय में कैप्चर करना होगा।

+1

मुझे नहीं लगता कि यह काम करता है .... जब UndoSetCashOnHand को बुलाया जाता है, तो इसे पूर्व-समय पर नकदऑनहैंड का मूल्य प्राप्त होगा, सेटकोएच समय पर नहीं। – Jimmy

+1

@ जिमी: यह बिल्कुल सही बात है। यही वह है जो उसका लैम्ब्डा * करता है, और वह पूछ रहा है कि इसके लिए कोई तरीका नहीं है * ऐसा करने के लिए * नहीं। जिस बिंदु को मैं बना रहा हूं वह यह समझ में नहीं आता है। कोड का उद्देश्य वैकल्पिक समाधान नहीं था, यह वास्तव में क्या कर रहा है उसका एक वैकल्पिक * प्रतिनिधित्व * है। –

+0

मैं देखता हूं। गलतफहमी के लिए माफी। – Jimmy

0

आप जो भी चाहते हैं उसे करने के लिए वास्तव में कोई अन्य जादुई तरीका नहीं है। संदर्भ का मूल्यांकन किया जाता है जब लैम्ब्डा को निष्पादित किया जाता है, पहले नहीं। जब आप लैम्ब्डा को जो भी कर रहे हैं उसके अलावा बनाया गया था तो उस मूल्य को "हुक" करने का स्वचालित तरीका नहीं है।

0

प्रतिनिधि भविष्य में चल रहा है .. I लगता है कि अस्थायी चर शायद "भविष्य में बजाए कोड कोड को संभालने का सबसे अच्छा तरीका है।" हालांकि, मुझे लगता है कि आप एक बाइंड() फ़ंक्शन कि एक प्रतिनिधि के लिए एक मौजूदा मूल्य बांधता है ..

Action Bind<T>(Func<T> f, T value) { 
    return (Action)(() => f(value)); 
} 
undoStack.Push(Bind(this.setCashOnHand, this.cashOnHand)); 
+2

ओह, करी एक बेहतर नाम है :) – Jimmy

0

खैर, अपने पूर्ववत ढेर केवल उदाहरण है कि अपने खुद के कार्यों जा नाश होगा द्वारा संदर्भित है, तो लिख सकता है कोई फर्क नहीं पड़ता कि।

उदाहरण के लिए:

public class MyType 
{ 

    private UndoStack undoStack {get;set;} 

    public void SetCashOnHand(int x) { 
    int coh = this.cashOnHand; 
    undo u =() => this.setCashOnHand(coh); 
    this.cashOnHand = x; 
    undoStack.Push(u); 
    } 
} 

तो यह क्या UndoStack संदर्भ फर्क नहीं पड़ता। यदि आप अंडोस्टैक इंजेक्शन कर रहे हैं और इस उदाहरण के संदर्भ कहीं और हैं तो इससे कोई फर्क नहीं पड़ता।

यदि दूसरा सत्य है, तो मैं पूर्ववत स्टैक के माध्यम से उदाहरणों को लीक करने के उदाहरणों को रोकने के लिए किसी प्रकार के कमजोर संदर्भ या अन्य चिनाई के साथ आने का प्रयास करने के बजाय इसे पुन: सक्रिय करने के बारे में देखता हूं।

मुझे लगता है कि आपके मामले में प्रत्येक स्तर को अपना स्वयं का पूर्ववत होना होगा। उदाहरण के लिए, यूआई परत को एक पूर्ववत स्टैक होना होगा जो उस उदाहरण को पॉप आउट करेगा जिसे अगली बार पूर्ववत करने की आवश्यकता है। या, यहां तक ​​कि, उदाहरणों के समूह जिन्हें पूर्ववत करने की आवश्यकता है, एक उपयोगकर्ता क्लिक के रूप में विभिन्न प्रकार के कई उदाहरणों को क्रम में पूर्ववत प्रक्रिया के माध्यम से जाना पड़ सकता है।

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