2010-01-20 7 views
10

मैं एक सी ++ डेवलपर हूं जो सी ++ में सिग्नल & स्लॉट का उपयोग करता है जो मुझे सी # में प्रतिनिधियों के समान लगता है। मैंने खुद को "बांध" द्वारा प्रदान की गई कार्यक्षमता की तलाश में एक नुकसान में पाया है, और मुझे लगता है कि मुझे कुछ याद आना चाहिए।(कैसे) एक अलग हस्ताक्षर के प्रतिनिधि के साथ काम करने के लिए एक विधि को बाध्य/पुनर्निर्मित करना संभव है?

मुझे लगता है कि निम्न की तरह कुछ ऐसा है, जो C++ में संभव है, प्रतिनिधियों के साथ सी # में संभव होना चाहिए।

Slot<void> someCallback; 

int foo(int i) 
{ 
    std::cout << "Value: " << i << "\n"; 
    return i; 
} 

int main() 
{ 
    int i = 0; 
    Slot<int> someCallback = bind(fun_ptr(foo), i); 
    ++i; // added to show that late evaluation would be a non-trivial difference 
    int result = someCallback(); 
    assert(result == 0); 
    return 0; 
} 

दुर्भाग्य से, मैं C# प्रतिनिधियों के संबंध में बाध्यकारी/rebinding के लिए किसी भी संदर्भ नहीं मिल पाई किया गया है: यहाँ मैं क्या C++ करना होगा के लिए कुछ psudo-कोड है। क्या मैं कुछ भूल रहा हूँ? सी # में ऐसा करने के लिए कुछ मूल रूप से अलग तरीका है?

उत्तर

13

सी # में हम कुछ इस तरह से करते हैं।

अगला, हम एक विधि Curry घोषित करते हैं जो Action<T> स्वीकार करता है और Action देता है। सामान्यतः, Action<T> एक प्रतिनिधि है जो T प्रकार का एक पैरामीटर स्वीकार करता है और void देता है। विशेष रूप से, Foo एक Action<int> है क्योंकि यह int प्रकार का एक पैरामीटर स्वीकार करता है और void देता है। Curry के रिटर्न प्रकार के लिए, इसे Action के रूप में घोषित किया गया है। एक Action एक प्रतिनिधि है जिसमें कोई पैरामीटर नहीं है और void देता है।

Curry की परिभाषा दिलचस्प है। हम लैम्ब्डा अभिव्यक्ति का उपयोग करके एक क्रिया को परिभाषित कर रहे हैं जो एक अज्ञात प्रतिनिधि का एक बहुत ही विशेष रूप है। प्रभावी ढंग से

() => action(parameter) 

का कहना है कि void पैरामीटर actionparameter पर मूल्यांकन किया जाता करने के लिए मैप किया गया है।

अंत में, Main में हम curried नामित Action का एक उदाहरण पैरामीटर 5 साथ Foo को Curry लागू करने का परिणाम है कि घोषित कर रहे हैं। यह आपके सी ++ उदाहरण में bind(fun_ptr(foo), 5) के समान भूमिका निभाता है।

आखिरकार, हम नए गठित प्रतिनिधि curried को वाक्यविन्यास curried() के माध्यम से आमंत्रित करते हैं। यह आपके उदाहरण में someCallback() जैसा है।

इसके लिए फैंसी शब्द currying है।

class Program { 
    static Func<TArg, TResult> Curry<TArg, TResult>(
     Func<TArg, TArg, TResult> func, 
     TArg arg1 
    ) { 
     return arg => func(arg1, arg); 
    } 

    static int Add(int x, int y) { 
     return x + y; 
    } 

    static void Main(string[] args) { 
     Func<int, int> addFive = Curry<int, int>(Add, 5); 
     Console.WriteLine(addFive(7)); 
    } 
} 

यहाँ हम एक विधि Curry कि एक प्रतिनिधि (Func<TArg, TArg, TResult> कि एक ही प्रकार TArg के दो पैरामीटर स्वीकार करता है और कुछ अन्य की एक मान देता है स्वीकार करता है की घोषणा कर रहे हैं:

एक और अधिक दिलचस्प उदाहरण के रूप में निम्नलिखित पर विचार TResult और प्रकार TArg की एक पैरामीटर टाइप करें और एक प्रतिनिधि है कि प्रकार TArg की एक एकल पैरामीटर स्वीकार करता है और प्रकार TResult (Func<TArg, TResult>) के एक मान देता है देता है।

फिर, एक परीक्षण के रूप में हम एक विधि Add घोषित करते हैं जो int प्रकार के दो पैरामीटर स्वीकार करता है और int (Func<int, int, int>) का पैरामीटर देता है। फिर Main में हम addFive नामक एक नए प्रतिनिधि को तुरंत चालू करते हैं जो एक विधि की तरह कार्य करता है जो इसके इनपुट पैरामीटर में पांच जोड़ता है। इस प्रकार

Console.WriteLine(addFive(7)); 

कंसोल पर 12 प्रिंट करता है।

+0

आपके विस्तृत उत्तर के लिए धन्यवाद। मैंने दूसरे को स्वीकृत उत्तर के रूप में चिह्नित किया क्योंकि यह अधिक संक्षिप्त है, हालांकि इसमें कुछ महत्वपूर्ण विवरण शामिल हैं जिनमें आपका शामिल है। – Catskul

+0

निश्चित रूप से। मुझे उम्मीद है कि अतिरिक्त रंग मदद करता है। :-) – jason

+0

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

4

भी सी ++ काउंटर हिस्सा

class Example { 
    static void foo(int i) { 
    Console.WriteLine(i); 
    } 
    static Action bind<T>(Action<T> action, T value) { 
    return() => action(value); 
    } 
    public static void Main() { 
    Action someCallback = bind(foo, 5); 
    someCallback(); 
    } 
} 

स्पष्टीकरण के करीब निम्नलिखित

class Example { 
    static void foo(int i) { 
    Console.WriteLine(i); 
    } 
    public static void Main() { 
    Action someCallback =() => foo(5); 
    someCallback(); 
    } 
} 

या के लिए कोई प्रयास करें। यहां क्या हो रहा है कि मैं लैम्ब्डा अभिव्यक्ति के माध्यम से एक नया प्रतिनिधि बना रहा हूं। लैम्ब्डा अभिव्यक्ति () => से शुरू होती है। इस मामले में यह कोई प्रतिनिधि स्वीकार नहीं करता है और कोई मूल्य नहीं बनाता है। यह Action प्रकार के साथ संगत है। बस Console.WriteLine बजाय std::cout करने के लिए उपयुक्त कॉल के साथ अपने विधि Foo को

class Program { 
    static Action Curry<T>(Action<T> action, T parameter) { 
     return() => action(parameter); 
    } 

    static void Foo(int i) { 
     Console.WriteLine("Value: {0}", i); 
    } 
    static void Main(string[] args) { 
     Action curried = Curry(Foo, 5); 
     curried(); 
    } 
} 

जाहिर विधि Foo मेल खाती है,:

+0

वाह। दिलचस्प। मैं यहाँ क्या देख रहा हूँ? – Catskul

+2

वह लैम्ब्डा अभिव्यक्ति का उपयोग करके एक नया प्रतिनिधि बना रहा है। प्रतिनिधि "फू (5)" कहते हैं। यह आपके लिए फू (5) पर कॉल करने के लिए फ्लाई पर एक नई विधि बनाने जैसा है, फिर इसे कुछ कॉलबैक प्रतिनिधि को सौंपना है। –

+0

'एक्शन ' ढांचा द्वारा प्रदान किया गया एक प्रतिनिधि है। यह एक ऐसा फ़ंक्शन है जो एक पैरामीटर (प्रकार टी) लेता है और कुछ भी नहीं देता (शून्य)। वह उस प्रतिनिधि को एक अज्ञात फ़ंक्शन असाइन कर रहा है (जिसे उसने 'कुछ कॉलबैक' नाम दिया है)। खाली माता-पिता इंगित करते हैं कि इसमें कोई तर्क नहीं होता है, '=>' के बाद अभिव्यक्ति फ़ंक्शन का मुख्य भाग है। – Sapph

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

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