फंक क्या है, इसका उपयोग कैसे और कब किया जाता है


115

क्या है Func<>और इसका उपयोग किस लिए किया जाता है?


4
यह एक विशिष्ट हस्ताक्षर के साथ प्रतिनिधियों के लिए सिर्फ एक शॉर्टकट है। नीचे दिए गए उत्तरों को पूरी तरह से समझने के लिए आपको प्रतिनिधियों को समझने की आवश्यकता होगी ;-)
Theo Lenndorff

2
@Oded के जवाब में यह कहता हैIf you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
LCJ

जवाबों:


76

Func<T>एक विधि के लिए एक पूर्वनिर्धारित प्रतिनिधि प्रकार है जो प्रकार का कुछ मूल्य लौटाता है T

दूसरे शब्दों में, आप इस प्रकार का उपयोग उस विधि को संदर्भित करने के लिए कर सकते हैं जो कुछ मूल्य देता है T। उदाहरण के लिए

public static string GetMessage() { return "Hello world"; }

इस तरह संदर्भित किया जा सकता है

Func<string> f = GetMessage;

लेकिन यह एक स्थिर एक-तर्क फ़ंक्शन =) का भी प्रतिनिधित्व कर सकता है
आर्क-कुन

2
@ आर्क-कुन नहीं, यह सही नहीं है। की परिभाषा Func<T>है delegate TResult Func<out TResult>()। कोई तर्क नहीं। Func<T1, T2>एक ऐसा कार्य होगा जो एक तर्क लेता है।
ब्रायन रासमुसेन

4
नहीं, मैं सही हूँ। static int OneArgFunc(this string i) { return 42; } Func<int> f = "foo".OneArgFunc;। =)
आर्क-कुन

1
यह एक विस्तार विधि है जो विशेष है।
ब्रायन रासमुसेन

इसके बारे में केवल विशेष बात यह Extensionविशेषता है जो केवल C # / VB.Net संकलक द्वारा पढ़ा जाता है, सीएलआर नहीं। मूल रूप से, उदाहरण के तरीकों (स्थिर कार्यों के विपरीत) में एक छिपा हुआ 0 वां "यह" पैरामीटर है। तो, 1-तर्क उदाहरण विधि 2-तर्क स्थिर फ़ंक्शन के समान है। फिर, हमारे पास प्रतिनिधि हैं जो लक्ष्य ऑब्जेक्ट और फ़ंक्शन पॉइंटर को स्टोर करते हैं । प्रतिनिधि लक्ष्य में पहला तर्क संग्रहीत कर सकते हैं या नहीं।
आर्क-कुन

87

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

उदाहरण के लिए, Enumerable.Selectविस्तार विधि पर विचार करें ।

  • पैटर्न है: के लिए एक दृश्य में हर आइटम, उस आइटम (जैसे, एक संपत्ति) से कुछ मूल्य का चयन करें और एक नया इन मूल्यों से मिलकर अनुक्रम पैदा करते हैं।
  • प्लेसहोल्डर है: कुछ चयनकर्ता समारोह है कि वास्तव में दृश्य के लिए मान हो जाता है ऊपर वर्णित है।

यह विधि Func<T, TResult>किसी भी ठोस कार्य के बजाय लेती है । यह इसे किसी भी संदर्भ में उपयोग करने की अनुमति देता है जहां उपरोक्त पैटर्न लागू होता है।

उदाहरण के लिए, मान लीजिए कि मेरे पास List<Person>सूची में प्रत्येक व्यक्ति का नाम है। मे यह कर सकती हु:

var names = people.Select(p => p.Name);

या कहो कि मुझे हर व्यक्ति की आयु चाहिए :

var ages = people.Select(p => p.Age);

तुरंत, आप देख सकते हैं कि कैसे मैं दो अलग-अलग कार्यों ( और ) के साथ एक पैटर्न (के साथ ) का प्रतिनिधित्व करने वाले समान कोड का लाभ उठाने में सक्षम था ।Selectp => p.Namep => p.Age

इसका विकल्प यह होगा कि Selectआप हर बार एक अलग तरह के मूल्य के लिए एक अनुक्रम स्कैन करना चाहते थे। तो ऊपर के रूप में एक ही प्रभाव को प्राप्त करने के लिए, मुझे आवश्यकता होगी:

// Presumably, the code inside these two methods would look almost identical;
// the only difference would be the part that actually selects a value
// based on a Person.
var names = GetPersonNames(people);
var ages = GetPersonAges(people);

प्लेसहोल्डर के रूप में अभिनय करने वाले एक प्रतिनिधि के साथ, मैं इस तरह के मामलों में खुद को एक ही पैटर्न पर लिखने से मुक्त करता हूं।


66

Func<T1, T2, ..., Tn, Tr> एक फ़ंक्शन का प्रतिनिधित्व करता है, जो (T1, T2, ..., Tn) तर्क और Tr लेता है।

उदाहरण के लिए, यदि आपके पास कोई फ़ंक्शन है:

double sqr(double x) { return x * x; }

आप इसे किसी प्रकार के फंक्शन-चर के रूप में सहेज सकते हैं:

Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;

और फिर ठीक वैसे ही उपयोग करें जैसे आप sqr का उपयोग करेंगे:

f1(2);
Console.WriteLine(f2(f1(4)));

आदि।

हालाँकि याद रखें, कि यह एक प्रतिनिधि है, और अधिक उन्नत जानकारी के लिए प्रलेखन देखें।


1
एक्सेलेंट उत्तर, लेकिन कीवर्ड स्टैटिक को कम्पाइल करने के लिए neeed है
boctulus

16

मुझे Func<T>बहुत उपयोगी लगता है जब मैं एक घटक बनाता हूं जिसे "मक्खी पर" व्यक्तिगत होने की आवश्यकता होती है।

यह एक बहुत ही सरल उदाहरण लें: एक PrintListToConsole<T>घटक।

एक बहुत ही सरल वस्तु जो वस्तुओं की इस सूची को कंसोल पर प्रिंट करती है। आप डेवलपर को इसका उपयोग करने देना चाहते हैं जो आउटपुट को निजीकृत करता है।

उदाहरण के लिए, आप उसे एक विशेष प्रकार के संख्या प्रारूप आदि को परिभाषित करने देना चाहते हैं।

फंक के बिना

सबसे पहले, आपको एक वर्ग के लिए एक इंटरफ़ेस बनाना होगा जो इनपुट लेता है और कंसोल को प्रिंट करने के लिए स्ट्रिंग पैदा करता है।

interface PrintListConsoleRender<T> {
  String Render(T input);
}

फिर आपको उस वर्ग को बनाना होगा PrintListToConsole<T>जो पहले बनाए गए इंटरफ़ेस को लेता है और सूची के प्रत्येक तत्व पर इसका उपयोग करता है।

class PrintListToConsole<T> {

    private PrintListConsoleRender<T> _renderer;

    public void SetRenderer(PrintListConsoleRender<T> r) {
        // this is the point where I can personalize the render mechanism
        _renderer = r;
    }

    public void PrintToConsole(List<T> list) {
        foreach (var item in list) {
            Console.Write(_renderer.Render(item));
        }
    }   
}

डेवलपर को आपके घटक का उपयोग करने की आवश्यकता है:

  1. इंटरफ़ेस लागू करें

  2. वास्तविक कक्षा पास करें PrintListToConsole

    class MyRenderer : PrintListConsoleRender<int> {
        public String Render(int input) {
            return "Number: " + input;
        }
    }
    
    class Program {
        static void Main(string[] args) {
            var list = new List<int> { 1, 2, 3 };
            var printer = new PrintListToConsole<int>();
            printer.SetRenderer(new MyRenderer());
            printer.PrintToConsole(list);
            string result = Console.ReadLine();   
        }   
    }

फंक का उपयोग करना बहुत सरल है

घटक के अंदर आप प्रकार का एक पैरामीटर को परिभाषित Func<T,String>है कि एक समारोह के लिए एक इंटरफेस का प्रतिनिधित्व करता है कि प्रकार टी के एक इनपुट पैरामीटर लेता है और एक स्ट्रिंग (कंसोल के लिए उत्पादन) रिटर्न

class PrintListToConsole<T> {

    private Func<T, String> _renderFunc;

    public void SetRenderFunc(Func<T, String> r) {
        // this is the point where I can set the render mechanism
        _renderFunc = r;
    }

    public void Print(List<T> list) {
        foreach (var item in list) {
            Console.Write(_renderFunc(item));
        }
    }
}

जब डेवलपर आपके घटक का उपयोग करता है तो वह केवल घटक के कार्यान्वयन के लिए पास Func<T, String>करता है, यह एक ऐसा फ़ंक्शन है जो कंसोल के लिए आउटपुट बनाता है।

class Program {
    static void Main(string[] args) {
        var list = new List<int> { 1, 2, 3 }; // should be a list as the method signature expects
        var printer = new PrintListToConsole<int>();
        printer.SetRenderFunc((o) => "Number:" + o);
        printer.Print(list); 
        string result = Console.ReadLine();
    }
}

Func<T>आपको मक्खी पर एक सामान्य विधि इंटरफ़ेस को परिभाषित करने देता है। आप परिभाषित करते हैं कि इनपुट किस प्रकार का है और आउटपुट किस प्रकार का है। सरल और संक्षिप्त।


2
इस मार्को को पोस्ट करने के लिए धन्यवाद। इसने वास्तव में मेरी मदद की है। मैं कुछ समय से फंक को समझने की कोशिश कर रहा हूं और अपनी प्रोग्रामिंग में भी सक्रिय रूप से इसका उपयोग करता हूं। इस उदाहरण से रास्ता साफ हो जाएगा। मुझे StampaFunc मेथड जोड़ना था क्योंकि मूल कोड में इसे छोड़ दिया गया था जो इसे प्रदर्शित करने से रोकता था।
सिवोकु एडिओला

1
मुझे लगता है कि फंक सैंपल में एक लाइन छूट गई है, प्रिंट फंक्शन या स्टैम्पफंक के लिए कॉल कहां है?
बशर अबू शमा

11

Func<T1,R>और अन्य पूर्वनिर्धारित सामान्य Funcप्रतिनिधियों ( Func<T1,T2,R>, Func<T1,T2,T3,R>और अन्य) सामान्य प्रतिनिधियों कि पिछले सामान्य पैरामीटर के प्रकार वापसी कर रहे हैं।

यदि आपके पास एक फ़ंक्शन है जो विभिन्न प्रकारों को वापस करने की आवश्यकता है, तो मापदंडों के आधार पर, आप ए का उपयोग कर सकते हैं Func प्रतिनिधि का , रिटर्न प्रकार निर्दिष्ट ।


7

यह सिर्फ एक पूर्वनिर्धारित जेनेरिक प्रतिनिधि है। इसका उपयोग करते हुए आपको प्रत्येक प्रतिनिधि को घोषित करने की आवश्यकता नहीं है। एक और पूर्वनिर्धारित प्रतिनिधि है, Action<T, T2...>जो एक ही है, लेकिन रिटर्न शून्य है।


0

शायद कुछ जानकारी जोड़ने में देर नहीं हुई है।

सम:

फंक सिस्टम नामस्थान में परिभाषित एक कस्टम प्रतिनिधि है जो आपको 0 से 16 इनपुट मापदंडों का उपयोग करके एक ही हस्ताक्षर (जैसा कि प्रतिनिधि करते हैं) के साथ एक विधि को इंगित करने की अनुमति देता है और उसे कुछ वापस करना होगा।

नामकरण और how2use:

Func<input_1, input_2, ..., input1_6, output> funcDelegate = someMethod;

परिभाषा:

public delegate TResult Func<in T, out TResult>(T arg);

इसका उपयोग कहां किया जाता है:

इसका उपयोग लंबोदर भाव और अनाम विधियों में किया जाता है।

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