एक चर के लिए कोड असाइन करना


124

क्या एक चर बनाना संभव है, और इसके लिए कोड की एक पंक्ति निर्दिष्ट करें, जैसे:

ButtonClicked = (MessageBox.Show("Hello, World!"));

... इसलिए जब मैं चर का उपयोग करता हूं, तो यह कोड की लाइन को निष्पादित करेगा।


100
+1 कोडिंग और एक अच्छा प्रश्न पूछने के लिए नया होने के दुर्लभ संयोजन के लिए: आप समझते हैं कि आप क्या करना चाहते हैं और इसे अच्छी तरह से समझाना चाहते हैं, आप बस इसके लिए शब्द नहीं जानते हैं, इसलिए आप इसे अपने दम पर नहीं पा सकते हैं।
टिम एस।

10
आपके द्वारा खोजा जा रहा शब्द एक प्रतिनिधि है
लास वी। कार्लसन

stackoverflow.com/questions/6187944/… इसे देखें, मुझे लगता है कि आपको पर्याप्त खोज करनी होगी। एस्प लगभग उस मामले में वाइनफॉर्म की तरह काम करता है।
CSharpie

ऑब्जेक्टिव-सी में बहुत कुछ लगता है जैसे
ब्रायन ट्रेसी

जवाबों:


89

आप इसे Actionइस तरह से असाइन कर सकते हैं :

var ButtonClicked = new Action(() => MessageBox.Show("hi"));

फिर इसे कॉल करें:

ButtonClicked();

पूर्णता के लिए (विभिन्न टिप्पणियों के संबंध में) ...

जैसा कि एरिक ने कहा, आप कोड की कई पंक्तियों को निष्पादित कर सकते हैं:

var ButtonClicked = new Action(() =>
{
    MessageBox.Show("hi");

    MessageBox.Show("something else");  // something more useful than another popup ;)
});

जैसा कि टिम ने कहा, आप Actionकीवर्ड को छोड़ सकते हैं

Action ButtonClicked = () => MessageBox.Show("hi");

Action ButtonClicked = () =>
{
    // multiple lines of code
};

केरेन की टिप्पणी को संबोधित करने के लिए, खाली कोष्ठक के बारे में, जो उन मापदंडों की सूची का प्रतिनिधित्व करता है जिन्हें आप एक्शन में भेजना चाहते हैं (इस मामले में, कोई नहीं)

, तो उदाहरण के लिए, आप दिखाने के लिए संदेश निर्दिष्ट करना चाहता है, तो आप एक पैरामीटर के रूप "संदेश" जोड़ सकता है (ध्यान दें कि मैं बदल Action करने के क्रम में एक भी स्ट्रिंग पैरामीटर निर्दिष्ट करने के लिए में) :Action<string>

Action<string> ButtonClicked = (message) => MessageBox.Show(message);

ButtonClicked("hello world!");

10
Action ButtonClicked = () => MessageBox.Show("hi");समतुल्य है और IMO नाइसर (यदि आप चाहें तो पार्न्स जोड़ें)
टिम एस।

1
कार्रवाई के लिए कोड की एक से अधिक लाइन को हल करना भी संभव है।
एरिक फिलिप्स

2
@CSharpie मुझे यकीन नहीं है कि यह धारणा ओपी के लिए मददगार है।
एरिक फिलिप्स

2
@CSharpie क्यों ओपी में इस का उपयोग नहीं कर सकता WinForms?
विविट

2
@CSharpie मैं देख रहा हूँ कि आप क्या कह रहे हैं। यदि वह वास्तव में इसे एक Button.Clickघटना में संलग्न कर रहा है , और इसे एक चर में संग्रहीत नहीं कर रहा है जो कि वह नाम के लिए हुआ है ButtonClicked
विवात

51

आपके मामले में, आप एक का उपयोग करना चाहते हैं delegate

आइए देखें कि एक प्रतिनिधि कैसे काम करता है और कैसे हम इसकी अवधारणा को समझकर एक आसान रूप प्राप्त कर सकते हैं:

// Create a normal function
void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();

आप देखते हैं, प्रतिनिधि एक सामान्य कार्य का रूप लेता है, लेकिन बिना किसी तर्क के (यह किसी भी अन्य विधि की तरह ही कोई भी तर्क ले सकता है, लेकिन सरलता के लिए, यह नहीं है)।

अब, हमारे पास जो है उसका उपयोग करते हैं; जैसे ही हम किसी अन्य चर को परिभाषित करेंगे हम प्रतिनिधि को परिभाषित करेंगे:

ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);

हमने मूल रूप से ButtonClicked नामक एक नया वैरिएबल बनाया है, जिसमें एक प्रकार का ButtonClick (जो एक डेलीगेट है) और जब उपयोग किया जाता है, तो OnButtonClick () विधि में विधि को निष्पादित करेगा।
इसका उपयोग करने के लिए हम बस कॉल करते हैं:ButtonClicked();

तो पूरा कोड होगा:

delegate void ButtonClick();

void OnButtonClick()
{
    MessageBox.Show("Hello World!");
}

void Foo()
{
    ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
    ButtonClicked(); // Execute the function.
}  

यहाँ से, हम लैम्ब्डा के भावों की ओर बढ़ सकते हैं और यह देख सकते हैं कि वे आपकी स्थिति में कैसे उपयोगी हो सकते हैं:
.NET लाइब्रेरीज़ द्वारा पहले से ही परिभाषित कई प्रतिनिधि हैं, जैसे कि एक्शन, जो किसी भी पैरामीटर को स्वीकार नहीं करते हैं और कोई मान नहीं लौटाते हैं। यह परिभाषित किया गया है कि public delegate void Action();
आप हर बार एक नए प्रतिनिधि को परिभाषित करने की आवश्यकता के बजाय इसे हमेशा अपनी आवश्यकताओं के लिए उपयोग कर सकते हैं। उदाहरण के लिए पिछले संदर्भ में, आप बस लिख सकते थे

Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();

जो किया होगा वही किया होगा।
अब जब आपने प्रतिनिधियों का उपयोग करने के विभिन्न तरीकों को देखा है, तो आइए हमारी पहली लैंबडा अभिव्यक्ति का उपयोग करें। लैम्ब्डा अभिव्यक्तियाँ अनाम फ़ंक्शन हैं; इसलिए, वे सामान्य कार्य हैं लेकिन एक नाम के बिना। वे उन रूपों के हैं:

x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");

हमारे मामले में, हमारे पास कोई पैरामीटर नहीं है इसलिए हम अंतिम अभिव्यक्ति का उपयोग करेंगे। हम इसे सिर्फ ऑनबटन क्लीक फ़ंक्शन के रूप में उपयोग कर सकते हैं, लेकिन हमें नामांकित फ़ंक्शन नहीं होने का लाभ मिलता है। हम इसके बजाय ऐसा कुछ कर सकते हैं:

Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );

या और भी आसान,

Action ButtonClicked = () => MessageBox.Show("Hello World!");

फिर बस कॉल ButtonClicked();के जरिये आपको कोड की बहु-लाइनें भी मिल सकती हैं, लेकिन मैं आपको अधिक भ्रमित नहीं करना चाहता। यह इस तरह दिखेगा हालांकि:

Action ButtonClicked = () => 
{
    MessageBox.Show("Hello World!");
};
ButtonClicked();

आप आसपास भी खेल सकते हैं, उदाहरण के लिए, आप इस तरह से किसी फंक्शन को अंजाम दे सकते हैं:

new Action(() => MessageBox.Show("Hello World!"))();

लंबे पोस्ट के लिए खेद है, आशा है कि यह बहुत भ्रामक नहीं था :)

संपादित करें: मैं यह उल्लेख करना भूल गया कि एक वैकल्पिक रूप जो भले ही अक्सर उपयोग नहीं किया जाता है, मेमने के भावों को समझना आसान बना सकता है:

new Action(delegate() {
    Console.WriteLine("I am parameterless");
})();

इसके अलावा, जेनरिक का उपयोग करना:

// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.
new Action<string>(delegate(string x) {
    Console.WriteLine(x);
})("I am a string parameter!");

बदले में आप लैम्बडा एक्सप्रेशन का उपयोग कर सकते हैं, लेकिन आपको पैरामीटर के प्रकार को परिभाषित करने के लिए (लेकिन कुछ मामलों में हो सकता है) की आवश्यकता नहीं है, उदाहरण के लिए, ऊपर दिए गए कोड को केवल इस प्रकार लिखा जा सकता है:

new Action<string>(x => {
    Console.WriteLine(x);
})("I am a string parameter!");

या:

new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");

EDIT2:
Action<string>का प्रतिनिधित्व कर रहा है public void delegate Action(string obj);
Action<string,string>का प्रतिनिधित्व है public void delegate Action(string obj, string obj2);
सामान्य में, Action<T>का प्रतिनिधित्व हैpublic void delegate Action<T>(T obj);

EDIT3: मुझे पता है कि पोस्ट कुछ समय के लिए यहां है, लेकिन मुझे लगता है कि यह उल्लेख नहीं करने के लिए वास्तव में अच्छा है: आप ऐसा कर सकते हैं, जो कि ज्यादातर आपके प्रश्न से संबंधित है:

dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");

या केवल:

Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");

7

Lazyवर्ग विशेष रूप से एक मूल्य की गणना की जा नहीं होगा जब तक आप इसे के लिए पूछने का प्रतिनिधित्व करने के लिए बनाया गया है। आप इसका निर्माण एक ऐसी विधि प्रदान करते हैं, जो यह बताती है कि इसका निर्माण कैसे किया जाना चाहिए, लेकिन यह उस पद्धति को एक से अधिक बार (यहां तक ​​कि मूल्य का अनुरोध करने वाले कई धागों के सामने भी) संभाल सकेगी और बस किसी भी अतिरिक्त अनुरोध के लिए पहले से निर्मित मूल्य को वापस कर देगी:

var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));

var result = foo.Value;

याद रखें कि Lazyउन मूल्यों के लिए उपयोग किया जाना चाहिए जिनके लिए बहुत अधिक प्रसंस्करण शक्ति की आवश्यकता होती है, और आपको उन्हें बातचीत के लिए उपयोग नहीं करना चाहिए (क्योंकि अर्थ .Valueयह है कि यह एक संपत्ति के समान एक मूल्य देता है, न कि एक (संवादात्मक) क्रिया)। इसके बजाय ऐसे कार्यों के लिए एक प्रतिनिधि का उपयोग किया जाना चाहिए।
हाबिल

1
@Abel नहीं, यह उन मानों के लिए नहीं है जिनके लिए बहुत अधिक प्रसंस्करण शक्ति की आवश्यकता होती है, यह किसी भी मूल्य के लिए है जिसे आप तब तक के प्रारंभ को स्थगित करना चाहते हैं, जब तक कि उस मूल्य को एक से अधिक बार प्रारंभ नहीं करना। के यहां दिया गया मान Value है इस्तेमाल किया; यह DialogResultसंदेश बॉक्स दिखाने से प्राप्त होता है। इस समाधान और एक प्रतिनिधि का उपयोग करने के बीच प्राथमिक अंतर यह है कि क्या प्रत्येक बार अनुरोध किए जाने या नहीं होने पर मूल्य को फिर से गणना की जानी चाहिए। आवश्यकताओं के बारे में मेरी व्याख्या यह थी कि यह वैचारिक रूप से एक मूल्य को शुरू कर रहा है, दोहराया जाने वाला कोई ऑपरेशन नहीं ।
सेविली

Lazyआसानी से गलत तरीके से इस्तेमाल किया जा सकता है। यह स्वयं का ओवरहेड है, एक छोटे से काम को टालने के लिए "बस" का उपयोग करने से यह लाभ से अधिक ओवरहेड को आमंत्रित करेगा। एक संपत्ति से मैसेजबॉक्स दिखाना सामान्य तौर पर बुरा व्यवहार है Lazy। Btw, MSDN से, मैं बोली: "किसी बड़ी या संसाधन-गहन वस्तु के निर्माण को स्थगित करने के लिए आलसी आरंभीकरण का उपयोग करें" । आप इससे असहमत हो सकते हैं, लेकिन मूल रूप से इसे डिजाइन किया गया था।
हाबिल

1
@ इस Lazyसंदर्भ में इस तरह से प्रदर्शन के लिए ओवरहेड निश्चित रूप से नगण्य है; यह एक संदेश बॉक्स पर क्लिक करने के लिए मानव की प्रतीक्षा में बिताए समय की तुलना में पीला हो जाएगा। यह ज्यादातर अंतर्निहित एप्लिकेशन की वास्तविक आवश्यकताओं के लिए नीचे आता है; प्रश्न की अस्पष्टता उद्देश्यपूर्ण सही उत्तर को असंभव बनाती है। यह प्रश्न की एक व्याख्या है। के रूप में एक संपत्ति पाने में बहुत काम करने के लिए खराब हो रहा है; स्पष्ट रूप से आप मौलिक रूप से संपूर्ण डिजाइन के विरोधी हैं Lazy। उस राय में आपका स्वागत है।
सेविली

क्षमा करें, आपने मुझे गलत समझा होगा। निश्चित रूप से, MessageBox ओवरहेड के साथ नगण्य है (मैं एक संपत्ति के अंदर यूआई का उपयोग नहीं करूंगा)। मेरा मतलब सामान्य रूप से छोटे कार्यों (जैसे डिफ्रेंसिंग 2 + 3 * 4 / i) से है, जहां क्लोजर बनाने का ओवरहेड स्वयं गणना से अधिक है। और मुझे लगता है कि मैं पूरी तरह से गले लगाता हूं Lazy, वास्तव में हम इसे एफ # में बहुत कम उपयोग करते हैं (सी # में थोड़ा कम) और हमने कठिन तरीका सीखा है कि आपको इसके साथ सावधान रहना होगा, esp। प्रदर्शन के संबंध में।
हाबिल

4

जिस तरह से मैं आपका प्रश्न पढ़ रहा हूं, यह GUI नियंत्रण के संदर्भ में है?

यदि यह WPF में है, तो नियंत्रण से कमांड को संभालने के लिए "सही" तरीके से देखें: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx

... लेकिन यह एक दर्द और अधिक दर्द हो सकता है। एक साधारण सामान्य मामले के लिए, आप एक इवेंट हैंडलर की तलाश कर सकते हैं, जैसे:

myButton.Click += (o, e) => MessageBox.Show("Hello, World!");

उस घटना हैंडलर को कई तरह से संभाला जा सकता है। उपरोक्त उदाहरण एक अनाम फ़ंक्शन का उपयोग करता है, लेकिन आप यह भी कर सकते हैं:

Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);

... जैसा आप पूछ रहे थे, एक फ़ंक्शन के साथ (या यहां, "एक्शन", क्योंकि यह शून्य है) एक चर के रूप में सौंपा गया है।


1

आप एक चर में C # कोड असाइन कर सकते हैं, इसे रनटाइम पर संकलित करके कोड चला सकते हैं:

  • अपना कोड लिखें:

    // Assign C# code to the code variable.
    string code = @"
    using System;
    
    namespace First
    {
        public class Program
        {
            public static void Main()
            {
                " +
                "Console.WriteLine(\"Hello, world!\");"
                + @"
            }
        }
    }
    ";
  • प्रदाता और कंपाइलर के पैरामीटर बनाएँ:

    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
  • संकलक के मापदंडों को परिभाषित करें:

    // Reference to System.Drawing library
    parameters.ReferencedAssemblies.Add("System.Drawing.dll");
    // True - memory generation, false - external file generation
    parameters.GenerateInMemory = true;
    // True - exe file generation, false - dll file generation
    parameters.GenerateExecutable = true;
  • संकलन सभा:

    CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
  • त्रुटियों की जाँच करें:

    if (results.Errors.HasErrors)
    {
            StringBuilder sb = new StringBuilder();
    
            foreach (CompilerError error in results.Errors)
            {
                    sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
            }
    
            throw new InvalidOperationException(sb.ToString());
    }
  • विधानसभा, प्रकार और मुख्य विधि प्राप्त करें:

    Assembly assembly = results.CompiledAssembly;
    Type program = assembly.GetType("First.Program");
    MethodInfo main = program.GetMethod("Main");
  • चलाओ:

    main.Invoke(null, null);

संदर्भ:

http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime


मुझे नहीं लगता कि गतिशील कोड संकलन पूछे गए प्रश्न के लिए प्रासंगिक था।
इरावनची
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.