आप C # में प्रतिनिधियों का उपयोग कब करेंगे? [बन्द है]


101

C # में प्रतिनिधियों का आपका क्या उपयोग है?


2
क्या आपका मतलब है कि .NET टाइप सिस्टम या C # डेलीगेट सिंटैक्स में डेलीगेट्स हैं? क्या आपका मतलब है "जब आप लैम्बडा एक्सप्रेशन सिंटैक्स के बजाय डेलिगेट सिंटैक्स का उपयोग करते हैं" या क्या आपका मतलब है "जब आप कक्षाओं / इंटरफेस / वर्चुअल तरीकों / आदि के बजाय डेलिगेट्स का उपयोग करते हैं?"
निकी

जवाबों:


100

अब जब हमारे पास C # में लैम्बडा एक्सप्रेशन और अनाम विधियाँ हैं, तो मैं डेलिगेट्स का बहुत अधिक उपयोग करता हूँ। C # 1 में, जहां आपके पास तर्क को लागू करने के लिए हमेशा एक अलग विधि होनी चाहिए, एक प्रतिनिधि का उपयोग करना अक्सर समझ में नहीं आता है। इन दिनों मैं प्रतिनिधियों का उपयोग करता हूं:

  • घटना संचालकों (जीयूआई और अधिक के लिए)
  • धागे शुरू
  • कॉलबैक (जैसे async APIs के लिए)
  • LINQ और समान (List.Find आदि)
  • कहीं और जहां मैं प्रभावी रूप से कुछ विशेष तर्क के साथ "टेम्पलेट" कोड लागू करना चाहता हूं (जहां प्रतिनिधि विशेषज्ञता प्रदान करता है)

पुश LINQ में "धक्का" का उल्लेख करते हुए?
मार्क Gravell

3
यकीन नहीं है कि मैं इसे और अधिक भ्रमित किए बिना संक्षिप्त रूप से कैसे समझाऊंगा :) (संभवतः यह घटना संचालकों, LINQ और टेम्प्लेट बिट द्वारा कवर किया गया है!
जॉन स्कीट

1
आपका पहला वाक्य ज्यादा मायने नहीं रखता है।
सेनफ

3
मुझे पता है कि आप क्या कहना चाह रहे हैं, लेकिन मुझे पढ़ने के लिए निम्नलिखित आसान मिलेगा: "अब जब हमारे पास C # में लंबोदर अभिव्यक्ति और गुमनाम तरीके हैं, तो मैं प्रतिनिधियों का उपयोग अधिक करता हूं।" मुझे पता है कि मैं नाइटपार्टिंग कर रहा हूं, लेकिन मुझे वास्तव में उस वाक्य को कुछ समय पहले पढ़ना था, इससे मुझे कोई मतलब नहीं था।
senfo

4
के लिए सम्मानित श्री स्कीट ;-) चुनौती देने के लिए साहसी +1
इंद्र

29

प्रतिनिधि कई उद्देश्यों के लिए बहुत उपयोगी होते हैं।

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

यहाँ एक मूर्खतापूर्ण उदाहरण दिया गया है - मुझे यकीन है कि आप इससे कुछ अधिक उपयोगी निकाल सकते हैं:

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

class Program
{
    static void Main()
    {
        List<String> names = new List<String>
        {
            "Nicole Hare",
            "Michael Hare",
            "Joe Hare",
            "Sammy Hare",
            "George Washington",
        };

        // Here I am passing "inMyFamily" to the "Where" extension method
        // on my List<String>.  The C# compiler automatically creates 
        // a delegate instance for me.
        IEnumerable<String> myFamily = names.Where(inMyFamily);

        foreach (String name in myFamily)
            Console.WriteLine(name);
    }

    static Boolean inMyFamily(String name)
    {
        return name.EndsWith("Hare");
    }
}

11
static Boolean inMyFamily(String name)विधि प्रतिनिधि है। जहां एक प्रतिनिधि को एक पैरामीटर के रूप में लिया जाता है। चूँकि प्रतिनिधि केवल कार्य बिंदु होते हैं, जब आप उस विधि का नाम पास करते हैं .Where(delegate)जो प्रतिनिधि बन जाता है। चूँकि inMyFamily एक बूलियन प्रकार देता है, इसे वास्तव में एक विधेय माना जाता है। विधेय केवल प्रतिनिधि हैं जो बूलियन्स लौटाते हैं।
लैंडन पॉच

4
"विधेय केवल प्रतिनिधि हैं जो बूलियन्स लौटाते हैं।" +1
डेहाई

@LandonPoch उस टिप्पणी को बेहतर तरीके से उत्तर में रखा गया होगा। मुझे एक शुरुआत करने वाला नहीं बना सकता है जहां यह था। धन्यवाद।
एककन गोपालकृष्णन

@ ईकन, मैं वास्तव में मुख्य सवाल का जवाब नहीं दे रहा था (जब आप प्रतिनिधियों का उपयोग करेंगे) तो मैंने इसे टिप्पणी के रूप में छोड़ दिया।
लैंडन पोच

14

एक और दिलचस्प जवाब मिला:

एक सहकर्मी ने मुझसे सिर्फ यह सवाल पूछा - .NET में प्रतिनिधियों का क्या मतलब है? मेरा उत्तर बहुत छोटा था और एक ऐसा जिसे उसने ऑनलाइन नहीं पाया था: एक विधि के निष्पादन में देरी के लिए।

स्रोत: LosTechies

जैसे LINQ कर रहा है।


+ 1. क्या उसने इस बारे में ऐसा नहीं सोचा। अच्छा बिंदु
Luke101

12

आप फ़ंक्शन-टाइप किए गए चर और मापदंडों को घोषित करने के लिए प्रतिनिधियों का उपयोग कर सकते हैं।

उदाहरण

"संसाधन उधार" पैटर्न पर विचार करें। आप किसी संसाधन के निर्माण और सफाई को नियंत्रित करना चाहते हैं, जबकि क्लाइंट कोड को बीच में संसाधन को "उधार" लेने की अनुमति देते हैं।

यह एक प्रतिनिधि प्रकार की घोषणा करता है।

public delegate void DataReaderUser( System.Data.IDataReader dataReader );

इस हस्ताक्षर से मेल खाने वाली किसी भी विधि का उपयोग इस प्रकार के प्रतिनिधि को तत्काल करने के लिए किया जा सकता है। C # 2.0 में, यह निहित रूप से किया जा सकता है, बस विधि के नाम का उपयोग करके, साथ ही अनाम विधियों का उपयोग करके।

यह विधि पैरामीटर के रूप में प्रकार का उपयोग करती है। प्रतिनिधि के आह्वान पर ध्यान दें।

public class DataProvider
{
    protected string _connectionString;

    public DataProvider( string psConnectionString )
    {
        _connectionString = psConnectionString;
    }

    public void UseReader( string psSELECT, DataReaderUser readerUser )
    {
        using ( SqlConnection connection = new SqlConnection( _connectionString ) )
        try
        {
            SqlCommand command = new SqlCommand( psSELECT, connection );
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();

            while ( reader.Read() )
                readerUser( reader );  // the delegate is invoked
        }
        catch ( System.Exception ex )
        {
            // handle exception
            throw ex;
        }
    }
}

फ़ंक्शन को एक अनाम विधि के साथ निम्नानुसार बुलाया जा सकता है। ध्यान दें कि अनाम विधि स्वयं के बाहर घोषित चर का उपयोग कर सकती है। यह बेहद आसान है (हालांकि उदाहरण थोड़ा विवादित है)।

string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";

DataProvider.UseReader( sQuery,
    delegate( System.Data.IDataReader reader )
    {
        Console.WriteLine( sTableName + "." + reader[0] );
    } );

11

प्रतिनिधि अक्सर एक विधि के साथ एक इंटरफ़ेस के स्थान पर उपयोग किया जा सकता है, इसका एक सामान्य उदाहरण पर्यवेक्षक पैटर्न होगा। अन्य भाषाओं में यदि आप एक सूचना प्राप्त करना चाहते हैं कि कुछ हुआ है तो आप कुछ इस तरह परिभाषित कर सकते हैं:

class IObserver{ void Notify(...); }

C # में यह आमतौर पर घटनाओं का उपयोग करके व्यक्त किया जाता है, जहां हैंडलर एक प्रतिनिधि है, उदाहरण के लिए:

myObject.SomeEvent += delegate{ Console.WriteLine("..."); };

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

myList.Where(i => i > 10);

उपरोक्त लंबोदर सिंटैक्स का एक उदाहरण है, जिसे निम्नानुसार भी लिखा जा सकता है:

myList.Where(delegate(int i){ return i > 10; });

एक और स्थान जहां प्रतिनिधियों का उपयोग करना उपयोगी हो सकता है, उदाहरण के लिए, कारखाने के कार्यों को पंजीकृत करना है:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);

आशा है कि ये आपकी मदद करेगा!


वाक्यविन्यास के साथ अच्छे उदाहरण .. धन्यवाद .. :)
रघु

10

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

NoDelegates.cs

using System;

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Test.checkInt(1);
        Test.checkMax(1);
        Test.checkMin(1);

        Test.checkInt(10);
        Test.checkMax(10);
        Test.checkMin(10);

        Test.checkInt(20);
        Test.checkMax(20);
        Test.checkMin(20);

        Test.checkInt(30);
        Test.checkMax(30);
        Test.checkMin(30);

        Test.checkInt(254);
        Test.checkMax(254);
        Test.checkMin(254);

        Test.checkInt(255);
        Test.checkMax(255);
        Test.checkMin(255);

        Test.checkInt(256);
        Test.checkMax(256);
        Test.checkMin(256);
    }
}

Delegates.cs

using System;

public delegate void Valid(int a);

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Valid v1 = new Valid(Test.checkInt);
        v1 += new Valid(Test.checkMax);
        v1 += new Valid(Test.checkMin);
        v1(1);
        v1(10);
        v1(20);
        v1(30);
        v1(254);
        v1(255);
        v1(256);
    }
}

5

प्रतिबिंब को गति देने के लिए थोड़ा अलग उपयोग है; हर बार प्रतिबिंब का उपयोग करने के बजाय, आप Delegate.CreateDelegateएक विधि (ए MethodInfo) के लिए एक (टाइप) प्रतिनिधि बनाने के लिए उपयोग कर सकते हैं , और उस प्रतिनिधि को इसके बजाय कॉल कर सकते हैं। यह तब प्रति कॉल बहुत तेज है, क्योंकि चेक पहले ही किए जा चुके हैं।

इसके साथ Expression, आप मक्खी पर कोड बनाने के लिए भी ऐसा ही कर सकते हैं - उदाहरण के लिए, आप आसानी से एक Expressionऐसा बना सकते हैं जो रनटाइम पर चुने गए प्रकार के लिए + ऑपरेटर का प्रतिनिधित्व करता है (जेनरिक के लिए ऑपरेटर समर्थन प्रदान करने के लिए, जो भाषा प्रदान नहीं करता है) ; और आप Expressionएक टाइप किए गए प्रतिनिधि को काम संकलित कर सकते हैं - काम किया।


5

प्रतिनिधि किसी भी समय आप घटनाओं का उपयोग करते हैं - यह वह तंत्र है जिसके द्वारा वे काम करते हैं।

इसके अलावा, LINQ क्वेरी का उपयोग करने जैसी चीजों के लिए प्रतिनिधि बहुत उपयोगी होते हैं। उदाहरण के लिए, कई LINQ क्वेरीज़ एक प्रतिनिधि (अक्सर Func<T,TResult>) लेती हैं जिसका उपयोग फ़िल्टरिंग के लिए किया जा सकता है।


4

घटनाओं के लिए आयोजकों की सदस्यता लेना


2

एक उदाहरण यहाँ देखा जा सकता है । आपके पास एक वस्तु को संसाधित करने की एक विधि है जो कुछ आवश्यकताओं को पूरा करती है। हालाँकि, आप ऑब्जेक्ट को कई तरीकों से संसाधित करने में सक्षम होना चाहते हैं। अलग-अलग विधियाँ बनाने के बजाय, आप बस एक मिलान विधि प्रदान कर सकते हैं जो किसी प्रतिनिधि के लिए ऑब्जेक्ट को संसाधित करता है और प्रतिनिधि को उस विधि से पास करता है जो ऑब्जेक्ट का चयन करता है। इस तरह, आप एक चयनकर्ता विधि के लिए विभिन्न तरीकों को असाइन कर सकते हैं। मैंने इसे आसानी से समझने की कोशिश की।


1

मैं थ्रेड्स के साथ संवाद करने के लिए प्रतिनिधियों का उपयोग करता हूं।

उदाहरण के लिए, मेरे पास एक जीत फ़ॉर्म ऐप हो सकता है जो एक फ़ाइल डाउनलोड करता है। एप्लिकेशन डाउनलोड करने के लिए एक श्रमिक सूत्र शुरू करता है (जो GUI को लॉक होने से रोकता है)। वर्कर थ्रेड प्रतिनिधियों को मुख्य कार्यक्रम में वापस भेजने के लिए स्थिति संदेश (जैसे डाउनलोड प्रगति) का उपयोग करता है, ताकि GUI स्टेटस बार को अपडेट कर सके।



0

ऑब्जर्वर / ऑब्जर्वेबल (घटनाओं) पैटर्न को बदलने के लिए उपयोग की पहली पंक्ति है। दूसरा, रणनीति पैटर्न का एक अच्छा सुरुचिपूर्ण संस्करण। विभिन्न अन्य usages को इकट्ठा किया जा सकता है, हालांकि इन पहले दो से अधिक गूढ़ मुझे लगता है।


0

ईवेंट, अन्य कोई भी ऑपरेशन


0

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


0

आलसी पैरामीटर आरंभीकरण! पिछले सभी उत्तरों (रणनीति पैटर्न, पर्यवेक्षक पैटर्न, आदि) के अलावा, प्रतिनिधि आपको मापदंडों के आलसी प्रारंभिककरण को संभालने की अनुमति देते हैं। उदाहरण के लिए, मान लें कि आपके पास एक फ़ंक्शन डाउनलोड () है जिसमें बहुत अधिक समय लगता है और एक निश्चित DownloadedObject देता है। यह ऑब्जेक्ट एक निश्चित शर्तों के आधार पर स्टोरेज द्वारा खपत होता है। आमतौर पर, आप:

storage.Store(conditions, Download(item))

हालाँकि, प्रतिनिधियों के साथ (अधिक सटीक रूप से, लैम्ब्डा) आप स्टोर के हस्ताक्षर को बदलकर निम्नलिखित कर सकते हैं ताकि यह एक शर्त और एक फंक <आइटम, DownloadedObject> प्राप्त करे और इसे इस तरह उपयोग करें:

storage.Store(conditions, (item) => Download(item))

इसलिए, भंडारण केवल प्रतिनिधि का मूल्यांकन करेगा यदि आवश्यक हो, शर्तों के आधार पर डाउनलोड निष्पादित करना।


{[वापसी] डाउनलोड करें (आइटम);} प्रतिनिधि (itemtype आइटम): - माइनर बिंदु है, लेकिन फिर "अधिक सटीक, lambdas" आप एक ही सी # 2.0 में एक गुमनाम विधि के साथ कर सकता है, हालांकि यह अधिक वर्बोज़ होगा
मार्क Gravell

यकीन है, LINQ के रूप में ही: lambdas प्रतिनिधियों के लिए सिंथेटिक चीनी से ज्यादा कुछ नहीं हैं। उन्होंने सिर्फ प्रतिनिधियों को अधिक सुलभ बनाया।
सेंटियागो प्लादिनो

लैंबडास केवल प्रतिनिधियों से थोड़ा अधिक है, क्योंकि वे अभिव्यक्ति पेड़ों के साथ-साथ प्रतिनिधियों के लिए परिवर्तनीय हैं।
जॉन स्कीट

खैर, लैम्ब्डा को भी एक्सप्रेशन के लिए संकलित किया जा सकता है, जो प्रतिनिधियों से पूरी तरह से अलग हैं । लेकिन आपके उदाहरण ने फंक <,> का उपयोग किया, जिसका उपयोग आनन-विधि से किया जा सकता है। अभिव्यक्तियाँ C # 2.0 में लिखना बेहद दर्दनाक होगा।
मार्क Gravell


0

तुलना सरणी में इन ऐरे.सोर्ट (टी [] सरणी, तुलना तुलना), सूची.शॉर्ट (तुलना तुलना), आदि


0

जहाँ तक मुझे पता है, प्रतिनिधियों को फंक्शन पॉइंटर्स में बदला जा सकता है। यह मूल कोड के साथ कार्य करते समय जीवन को आसान बनाता है, जो कि फ़ंक्शन पॉइंटर्स को लेता है, क्योंकि वे प्रभावी रूप से ऑब्जेक्ट-ओरिएंटेड हो सकते हैं, भले ही मूल प्रोग्रामर ने ऐसा करने के लिए कोई प्रावधान नहीं किया था।


0

प्रतिनिधि द्वारा किसी विधि को कॉल करने के लिए इसका उपयोग किया जाता है। उदाहरण के लिए:

  delegate void del_(int no1,int no2);
class Math
{
   public static void add(int x,int y)
   {
     Console.WriteLine(x+y);
   }
   public static void sub(int x,int y)
   {
     Console.WriteLine(x-y);
   }
}



    class Program
    {
        static void Main(string[] args)
        {
            del_ d1 = new del_(Math.add);
            d1(10, 20);
            del_ d2 = new del_(Math.sub);
            d2(20, 10);
            Console.ReadKey();
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.