एक शब्दकोश में सी # स्टोर कार्य करता है


93

मैं एक शब्दकोश कैसे बनाऊं जहां मैं फ़ंक्शंस संग्रहीत कर सकता हूं?

धन्यवाद।

मेरे पास लगभग 30+ फ़ंक्शन हैं जिन्हें उपयोगकर्ता से निष्पादित किया जा सकता है। मैं फ़ंक्शन को इस तरह निष्पादित करने में सक्षम होना चाहता हूं:

   private void functionName(arg1, arg2, arg3)
   {
       // code
   }

   dictionaryName.add("doSomething", functionName);

    private void interceptCommand(string command)
    {
        foreach ( var cmd in dictionaryName )
        {
            if ( cmd.Key.Equals(command) )
            {
                cmd.Value.Invoke();
            }
        }
    }

हालाँकि, फ़ंक्शन हस्ताक्षर हमेशा समान नहीं होते हैं, इस प्रकार विभिन्न तर्क होते हैं।


5
यह एक शानदार मुहावरा है - बुरा स्विच स्टेटमेंट बदल सकता है।
हमीश ग्रुबीजन

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

1
@ HamishGrubijan, यदि आप एक स्विच स्टेटमेंट को बदलने के लिए ऐसा करते हैं तो आप सभी संकलन समय अनुकूलन और स्पष्टता को छोड़ रहे हैं। तो, मैं कहूंगा कि यह मुहावरे की तुलना में अधिक मूर्ख था। यदि आप एक तरह से गतिशील रूप से मानचित्र की कार्यक्षमता चाहते हैं जो रनटाइम में भिन्न हो सकती है, तो, यह उपयोगी हो सकता है।
जॉडरेल

12
@ जोडरेल, ए) इडियट एक मजबूत शब्द है जो रचनात्मक नहीं है, बी) स्पष्टता एक देखने वाले की आंखों में है। मैंने बहुत सारे बदसूरत स्विच स्टेटमेंट देखे हैं। सी) संकलन समय अनुकूलन इस धागे पर ... Zooba विपरीत के लिए तर्क है stackoverflow.com/questions/505454/... स्विच बयान है हे (लॉग एन), तो यह गति कुछ अलग करने के लिए 100 + मामलों को शामिल करने के लिए होता है, तो । यह पठनीय नहीं है, बिल्कुल। शायद एक स्विच स्टेटमेंट एक सही हैश फ़ंक्शन का उपयोग कर सकता है, लेकिन केवल एक छोटे से # मामलों के लिए। यदि आप .Net का उपयोग कर रहे हैं, तो आप माइक्रोसेकंड के ऊपर झल्लाहट नहीं करते हैं।
हामिश ग्रुबीजान

4
@Jodrell, (जारी) यदि आप अपने हार्डवेयर से सबसे अधिक निचोड़ना चाहते हैं, तो आप उस क्रम में ASM, C, या C ++ का उपयोग करते हैं। .Net में शब्दकोश खोज आपको नहीं मारेगी। प्रतिनिधियों के विभिन्न हस्ताक्षर - यह सबसे मजबूत बिंदु है जो आपने एक सरल शब्दकोश दृष्टिकोण का उपयोग करने के खिलाफ किया था।
हामिश ग्रुबीजान

जवाबों:


120

ऐशे ही:

Dictionary<int, Func<string, bool>>

यह आपको फ़ंक्शन को स्टोर करने की अनुमति देता है जो एक स्ट्रिंग पैरामीटर लेते हैं और बूलियन वापस करते हैं।

dico[5] = foo => foo == "Bar";

या यदि फ़ंक्शन अनाम नहीं है:

dico[5] = Foo;

जहां फू को इस तरह परिभाषित किया गया है:

public bool Foo(string bar)
{
    ...
}

अपडेट करें:

आपके अपडेट को देखने के बाद ऐसा लगता है कि आप उस फ़ंक्शन के हस्ताक्षर को पहले से नहीं जानते हैं जिसे आप आमंत्रित करना चाहते हैं। किसी फ़ंक्शन को लागू करने के लिए .NET में आपको सभी तर्कों को पारित करने की आवश्यकता होती है और यदि आप नहीं जानते हैं कि प्रतिबिंब के माध्यम से इसे प्राप्त करने के लिए तर्क क्या होने जा रहे हैं।

और यहाँ एक और विकल्प है:

class Program
{
    static void Main()
    {
        // store
        var dico = new Dictionary<int, Delegate>();
        dico[1] = new Func<int, int, int>(Func1);
        dico[2] = new Func<int, int, int, int>(Func2);

        // and later invoke
        var res = dico[1].DynamicInvoke(1, 2);
        Console.WriteLine(res);
        var res2 = dico[2].DynamicInvoke(1, 2, 3);
        Console.WriteLine(res2);
    }

    public static int Func1(int arg1, int arg2)
    {
        return arg1 + arg2;
    }

    public static int Func2(int arg1, int arg2, int arg3)
    {
        return arg1 + arg2 + arg3;
    }
}

इस दृष्टिकोण के साथ आपको अभी भी पैरामीटर की संख्या और प्रकार को जानना होगा जो कि शब्दकोश के संबंधित सूचकांक में प्रत्येक फ़ंक्शन को पारित करने की आवश्यकता है या आपको रनटाइम त्रुटि मिलेगी। और अगर आपके फ़ंक्शंस के बदले रिटर्न वैल्यूज़ का उपयोग नहीं होता System.Action<>है System.Func<>


समझा। मुझे लगता है कि मुझे प्रतिबिंब के बारे में पढ़ने में कुछ समय बिताना होगा, मदद की सराहना करें।
ची

@chi, मेरा आखिरी अपडेट देखें। मैंने के साथ एक उदाहरण जोड़ा है Dictionary<int, Delegate>
डारिन दिमित्रोव

3
मैं नीचे नहीं जाऊंगा, लेकिन मुझे सिर्फ यह कहना पड़ेगा कि इस तरह का कार्यान्वयन बहुत अच्छे कारणों के बिना एक एंटीपैटर्न है। यदि ओपी ग्राहकों से फ़ंक्शन के सभी तर्कों में पारित होने की उम्मीद करता है, तो पहले स्थान पर एक फ़ंक्शन तालिका क्यों है? क्यों ग्राहक बस नहीं फोन गतिशील आह्वान के जादू के बिना काम करता है?
जूलियट

1
@ जूलियट, मैं आपसे सहमत हूं, मैंने कभी नहीं कहा कि यह अच्छी बात है। मेरे उत्तर में जिस तरह से मैंने इस तथ्य पर जोर दिया कि हमें अभी भी पैरामीटर की संख्या और प्रकार को जानने की आवश्यकता है जो कि शब्दकोश के संबंधित सूचकांक में प्रत्येक फ़ंक्शन को पारित करने की आवश्यकता है। आप इस ओर इशारा करते हुए पूरी तरह से सही हैं कि इस मामले में हमें शायद हैशटेबल की भी आवश्यकता नहीं है क्योंकि हम सीधे फ़ंक्शन को लागू कर सकते हैं।
डारिन दिमित्रोव

1
क्या होगा यदि मुझे एक फ़ंक्शन को स्टोर करने की आवश्यकता है जो कोई तर्क नहीं लेता है और कोई वापसी मूल्य नहीं है?
डेटाग्रेड सेप

8

हालाँकि, फ़ंक्शन हस्ताक्षर हमेशा समान नहीं होते हैं, इस प्रकार विभिन्न तर्क होते हैं।

इस तरह परिभाषित कुछ कार्यों के साथ शुरू करते हैं:

private object Function1() { return null; }
private object Function2(object arg1) { return null; }
private object Function3(object arg1, object arg3) { return null; }

आपके पास अपने निपटान में वास्तव में 2 व्यवहार्य विकल्प हैं:

1) ग्राहकों को अपने फ़ंक्शन को सीधे कॉल करके प्रकार-सुरक्षा बनाए रखें।

यह शायद सबसे अच्छा समाधान है, जब तक कि आपके पास इस मॉडल से टूटने के बहुत अच्छे कारण नहीं हैं।

जब आप फ़ंक्शन कॉल को इंटरसेप्ट करना चाहते हैं, तो यह मुझे लगता है कि आप वर्चुअल फ़ंक्शंस का पुनः आविष्कार करने की कोशिश कर रहे हैं। इस तरह की कार्यक्षमता को बॉक्स से बाहर निकालने के तरीकों का एक नाव लोड है, जैसे कि बेस क्लास से विरासत में मिली अपने कार्यों को ओवरराइड करना।

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

public interface IMyObject
{
    object Function1();
    object Function2(object arg1);
    object Function3(object arg1, object arg2);
}

class MyObject : IMyObject
{
    public object Function1() { return null; }
    public object Function2(object arg1) { return null; }
    public object Function3(object arg1, object arg2) { return null; }
}

class MyObjectInterceptor : IMyObject
{
    readonly IMyObject MyObject;

    public MyObjectInterceptor()
        : this(new MyObject())
    {
    }

    public MyObjectInterceptor(IMyObject myObject)
    {
        MyObject = myObject;
    }

    public object Function1()
    {
        Console.WriteLine("Intercepted Function1");
        return MyObject.Function1();
    }
    public object Function2(object arg1)
    {
        Console.WriteLine("Intercepted Function2");
        return MyObject.Function2(arg1);
    }

    public object Function3(object arg1, object arg2)
    {
        Console.WriteLine("Intercepted Function3");
        return MyObject.Function3(arg1, arg2);
    }
}

2) या अपने कार्यों के इनपुट को एक सामान्य इंटरफ़ेस में मैप करें।

यदि आपके सभी कार्य संबंधित हैं तो यह काम कर सकता है। उदाहरण के लिए, यदि आप एक खेल लिख रहे हैं, और सभी फ़ंक्शन खिलाड़ी या खिलाड़ी की इन्वेंट्री के कुछ हिस्से के लिए कुछ करते हैं। आप कुछ इस तरह से समाप्त करेंगे:

class Interceptor
{
    private object function1() { return null; }
    private object function2(object arg1) { return null; }
    private object function3(object arg1, object arg3) { return null; }

    Dictionary<string, Func<State, object>> functions;

    public Interceptor()
    {
        functions = new Dictionary<string, Func<State, object>>();
        functions.Add("function1", state => function1());
        functions.Add("function2", state => function2(state.arg1, state.arg2));
        functions.Add("function3", state => function3(state.arg1, state.are2, state.arg3));
    }

    public object Invoke(string key, object state)
    {
        Func<object, object> func = functions[key];
        return func(state);
    }
}

मेरी धारणा एक objectऐसी होगी जो एक नए थ्रेड को दी जाएगी।
स्कॉट फ्रैले

1

अरे, मुझे आशा है कि यह मदद करता है। आप किस भाषा से आ रहे हैं?

internal class ForExample
{
    void DoItLikeThis()
    {
        var provider = new StringMethodProvider();
        provider.Register("doSomethingAndGetGuid", args => DoSomeActionWithStringToGetGuid((string)args[0]));
        provider.Register("thenUseItForSomething", args => DoSomeActionWithAGuid((Guid)args[0],(bool)args[1]));


        Guid guid = provider.Intercept<Guid>("doSomethingAndGetGuid", "I don't matter except if I am null");
        bool isEmpty = guid == default(Guid);
        provider.Intercept("thenUseItForSomething", guid, isEmpty);
    }

    private void DoSomeActionWithAGuid(Guid id, bool isEmpty)
    {
        // code
    }

    private Guid DoSomeActionWithStringToGetGuid(string arg1)
    {
        if(arg1 == null)
        {
            return default(Guid);
        }
        return Guid.NewGuid();
    }

}
public class StringMethodProvider
{
    private readonly Dictionary<string, Func<object[], object>> _dictionary = new Dictionary<string, Func<object[], object>>();
    public void Register<T>(string command, Func<object[],T> function)
    {
        _dictionary.Add(command, args => function(args));
    }
    public void Register(string command, Action<object[]> function)
    {
        _dictionary.Add(command, args =>
                                     {
                                         function.Invoke(args);
                                         return null;
                                     } );
    }
    public T Intercept<T>(string command, params object[] args)
    {
        return (T)_dictionary[command].Invoke(args);
    }
    public void Intercept(string command, params object[] args)
    {
        _dictionary[command].Invoke(args);
    }
}

1

params object[] listपद्धति के मापदंडों का उपयोग क्यों न करें और अपने तरीकों (या कॉलिंग लॉजिक) के अंदर कुछ सत्यापन करें, यह मापदंडों की एक चर संख्या के लिए अनुमति देगा।


1

निम्नलिखित परिदृश्य आपको इनपुट मापदंडों के रूप में भेजने और आउटपुट मापदंडों के समान ही प्राप्त करने के लिए तत्वों के शब्दकोश का उपयोग करने की अनुमति देगा।

पहले शीर्ष पर निम्नलिखित पंक्ति जोड़ें:

using TFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Collections.Generic.IDictionary<string, object>>;

फिर अपनी कक्षा के अंदर, शब्दकोश को इस प्रकार परिभाषित करें:

     private Dictionary<String, TFunc> actions = new Dictionary<String, TFunc>(){

                        {"getmultipledata", (input) => 
                            {
                                //DO WORKING HERE
                                return null;
                            } 
                         }, 
                         {"runproc", (input) => 
                            {
                                //DO WORKING HERE
                                return null;
                            } 
                         }
 };

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

var output = actions["runproc"](inputparam);

0

शब्दकोश को परिभाषित करें और System.Actionप्रकार के रूप में उपयोग करते हुए फ़ंक्शन संदर्भ को मूल्य के रूप में जोड़ें :

using System.Collections;
using System.Collections.Generic;

public class Actions {

    public Dictionary<string, System.Action> myActions = new Dictionary<string, System.Action>();

    public Actions() {
        myActions ["myKey"] = TheFunction;
    }

    public void TheFunction() {
        // your logic here
    }
}

फिर इसके साथ आह्वान करें:

Actions.myActions["myKey"]();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.