সি # একটি অভিধানে স্টোর ফাংশন


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();
            }
        }
    }

যাইহোক, ফাংশন স্বাক্ষর সবসময় এক রকম হয় না, এভাবে বিভিন্ন পরিমাণ যুক্তিযুক্ত থাকে।


7
এটি একটি দুর্দান্ত প্রতিমা - দুষ্টু সুইচ বিবৃতি প্রতিস্থাপন করতে পারে।
হামিশ গ্রুবিজন

4
এটি আমার দ্বারা একটি খারাপভাবে লিখিত উদাহরণ ছিল। আমি এমন কোনও অভিধান তৈরি করতে জানি না যা এটি করবে, কারণ ফাংশনের স্বাক্ষর সর্বদা আলাদা।
চি

4
@ হামিশগ্রিবিজান, আপনি যদি একটি স্যুইচ স্টেটমেন্ট প্রতিস্থাপনের জন্য এটি করেন তবে আপনি সমস্ত সংকলন সময়ের অপ্টিমাইজেশন এবং স্পষ্টতা বর্জন করছেন। সুতরাং, আমি বলব এটি মূর্খতার চেয়ে বোকা। আপনি যদি রানটাইমের সময় বিভিন্নভাবে পরিবর্তিত হতে পারে এমনভাবে কার্যকরীতার গতিশীল মানচিত্র করতে চান, তবে এটি কার্যকর হতে পারে।
জোডরেল

15
@ জোডরেল, ক) ইডিয়ট একটি শক্ত শব্দ যা গঠনমূলক নয়, খ) স্পষ্টতা দর্শকের চোখে the আমি প্রচুর কুৎসিত সুইচ স্টেটমেন্ট দেখেছি। গ) টাইম অপ্টিমাইজেশানটি সঙ্কলন করুন ... এই থ্রেডগুলিতে জুবা বিপরীত স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 505454/২ এর পক্ষে যুক্তি দেখায় যদি স্যুইচ স্টেটমেন্টগুলি ও (লগ এন) হয় তবে গতি বাড়ানোর জন্য এটিতে 100+ কেস থাকতে হবে । এটি অবশ্যই পঠনযোগ্য নয়। হতে পারে একটি স্যুইচ বিবৃতি একটি নিখুঁত হ্যাশ ফাংশন ব্যবহার করতে পারে, তবে কেবলমাত্র # ছোট ক্ষেত্রে। আপনি যদি নেট ব্যবহার করে থাকেন, তবে আপনি মাইক্রোসেকেন্ডগুলিতে ফেটে পড়বেন না।
হামিশ গ্রুবিজন

4
@ জোডরেল, (অব্যাহত) আপনি যদি নিজের হার্ডওয়ারের বেশিরভাগ অংশটিকে মুছতে চান, তবে আপনি সেই ক্রমে ASM, C বা C ++ ব্যবহার করুন। .Net অভিধানের অনুসন্ধানে আপনাকে হত্যা করবে না। প্রতিনিধিদের বিভিন্ন স্বাক্ষর - এটি একটি সর্বাধিক শক্তিশালী পয়েন্ট যা আপনি একটি সাধারণ অভিধান পদ্ধতির ব্যবহারের বিরুদ্ধে করেছেন।
হামিশ গ্রুবিজন

উত্তর:


121

এটার মত:

Dictionary<int, Func<string, bool>>

এটি আপনাকে এমন ফাংশন সংরক্ষণ করতে দেয় যা স্ট্রিং প্যারামিটার নেয় এবং বুলিয়ান ফেরত দেয়।

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

বা যদি ফাংশনটি বেনামে না থাকে:

dico[5] = Foo;

যেখানে ফু এর সংজ্ঞা দেওয়া হয়েছে:

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

হালনাগাদ:

আপনার আপডেটটি দেখার পরে মনে হচ্ছে যে আপনি যে ফাংশনটি করতে চান তা স্বাক্ষর আপনি আগেই জানেন না advance .NET এ কোনও ক্রিয়াকলাপটি শুরু করার জন্য আপনাকে সমস্ত আর্গুমেন্টগুলি পাস করতে হবে এবং যদি আপনি জানেন না যে আর্গুমেন্টগুলি কী অর্জন করতে পারে এটিই কেবল প্রতিফলনের মাধ্যমে achieve

এবং এখানে আরও একটি বিকল্প রয়েছে:

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<>


আমি দেখি. আমার ধারণা আমি তখন প্রতিচ্ছবি সম্পর্কে পড়তে কিছুটা সময় ব্যয় করতে হবে, সাহায্যের প্রশংসা করব।
চি

@চি, আমার শেষ আপডেট দেখুন। আমি সাথে একটি উদাহরণ যুক্ত করেছি Dictionary<int, Delegate>
দারিন দিমিত্রভ

4
আমি হ্রাস করব না, তবে আমাকে কেবল বলতে হবে এই ধরণের বাস্তবায়ন খুব ভাল কারণ ছাড়াই একটি প্রতিষেধক । যদি ওপি আশা করে যে ক্লায়েন্টরা সমস্ত আর্গুমেন্টে ফাংশনটি পাস করবে, তবে কেন প্রথম স্থানে একটি ফাংশন টেবিল থাকবে? ডায়ামিক চালানের যাদু ছাড়া ক্লায়েন্ট কেবল ফাংশনগুলি কল করে না কেন ?
জুলিয়েট

4
@ জুলিয়েট, আমি আপনার সাথে একমত, আমি কখনও বলিনি যে এটি একটি ভাল জিনিস। আমার উত্তরের পথে আমি এই বিষয়টির উপর জোর দিয়েছিলাম যে অভিধানের সংশ্লিষ্ট সূচকটিতে প্রতিটি ফাংশনে পাস করা দরকার যে পরামিতিগুলির সংখ্যা এবং প্রকারের এখনও আমাদের জানা দরকার। আপনি একেবারে সঠিকভাবে উল্লেখ করে বলেছেন যে এই ক্ষেত্রে আমাদের সম্ভবত একটি হ্যাশটেবলের প্রয়োজন নেই কারণ আমরা সরাসরি ফাংশনটি শুরু করতে পারি।
দারিন দিমিত্রভ

4
আমার যদি এমন কোনও ক্রিয়াকলাপ সংরক্ষণ করতে হবে যা কোনও যুক্তি না নেয় এবং কোনও ফেরতের মান না থাকে?
ডেটাগ্রিড

8

যাইহোক, ফাংশন স্বাক্ষর সবসময় এক রকম হয় না, এভাবে বিভিন্ন পরিমাণ যুক্তিযুক্ত থাকে।

এর মতো সংজ্ঞায়িত কয়েকটি ফাংশন দিয়ে শুরু করা যাক:

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

আপনার কাছে সত্যিই আপনার কাছে দুটি কার্যকর বিকল্প রয়েছে:

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যা একটি নতুন থ্রেডে পাঠানো হবে।
স্কট ফ্রেলে

2

অভিধানটি সংজ্ঞায়িত করুন এবং 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"]();

99% ক্ষেত্রে এখন পর্যন্ত সাধারণ উত্তর।
ফ্যাটি

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);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.