Click here to Skip to main content
15,867,986 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Recently I have read one article in website code project regarding delegate
I appriciate that it was shot and simlpe I got basic idea out of that
I have a silly doubt please clear me:confused:


While I do coding I can call any method like this
eg :
obj1.Metho1();
obj1.Method();
As per the explanation I understood that we call the function like this

eg:
Delegate_Multicast func = new Delegate_Multicast(Method1);
func += new Delegate_Multicast(Method2);
func(1,2);             // Method1 and Method2 are called
func -= new Delegate_Multicast(Method1);
func(2,3);
As per my understanding both ways are giving same result and same effort of coding.

If I want to execute Method1 and Method2 I have to attach these methods seperatly to the delegate

so I dont understand where we can get the advantage of using delegate featue rather than going into old style of method calling. can anyone please explain X|
Posted
Updated 31-Jan-11 17:47pm
v2

Well, if you try to create artificially simplified use cases as you present in your Question, you don't have a chance to see "Extra Advantage", right?

I would prefer talking not about "advantage", but about a principal technological feature. What's so special about delegates; what is the useful effect which we cannot achieve without them?

Let's step back and consider the simplest and most fundamental aspect of delegation, because if you understand it, you can derive all advanced uses. We should come to the case where we get some profit not achievable using customary methods. (I'm not going to touch multicast feature, because it is even irrelevant.)

First of all, let's use the word "delegate" only for a delegate type, and the instances of a delegate types call "delegate instance", not mixing them. First, it is important to understand, that a delegate instance is a variable of a method parameter. That said, delegate instances are considered as "first-class citizens" objects. At the same time, a delegate instance represents some method (anonymous or not), in this way, methods can be considered as "first-class citizens" objects.

Now, this is the time to consider anatomy of a delegate instance. For our current purpose, we can consider a delegate instance as a data structure of two essential parts: a reference to the code entry point and a reference to some object of the class. The reference to object can be null, for static methods. In other words, we have a class C, the method C.M, C.S (let's make a second one static) and an instance of this class cinst:

C#
class C {
    public delegate void DeletateType(/*...*/);
    //return types can be different; I use void for simplicity
    internal void M(/*...*/) {/*...*/};
    internal static void S(/*...*/) {/*...*/}
}
//...
C cinst = new C(/*...*/);


Based on that, we can have two delegate instances: [C.M, cinst] and [C.S, null], importantly, cinst is the instance of the same class as the method. (There is also a reference to delegate type meta-data, let's forget it for a while.)

As you should understand, every instance method is called having additional parameter this (absent in static methods) used to carry a reference to the instance. Having a data structure like in my pseudo-code [C.M, cinst], we have everything to call a method: we call at the entry point C.M and use this=cinst as a first parameter, other parameters are passes explicitly, according to the delegate type.

Now, let's remember the delegate instance is a variable and can be passed as a method parameter. So, we can have completely unrelated class using C.DelegateType as an additional level of abstraction:

C#
class DelegateUser {
    internal void CompositeAction(
         int data,
         C.DelegateType injectedAction,
         /*some type(s)*/ injectedActionParameter) {
        //do something with first parameter: data
        //call action from second parameter:
        if (injectedAction != null)
            //instance of C (for example) passed as hidden parameter:
            injectedAction(injectedActionParameter); 
    } //CompositeAction
} //DelegateUser

//...

//In this way, we can call CompositeAction with different instances (apparently)
//of different methods (aha! -- of matching profile, of course)
//of different classes (important and not trivial!):

DelegateUser user = new DelegateUser( //...
user.C CompositeAction(3, new C(/*...*/).M(4, /*...*/);
//Profit: can use different class, other then C, different methods, etc. 


This can be considered as a different flexibility on top of "classical" OOP. Of cource we could call different versions of injectedAction if we make it a virtual function, so it will be different through late binding, but it should be a method of a class from the same class hierarchy. The delegate is more of ad-hoc, but more flexible method.

There are a lot of uses of this behefit. Most basic is passing a delegate to provide an arbitrary predicate method to some complex method, for example, traversing some data:

C#
void TraverseData(
         MyDataContainer data,
         Func<DataElement> predicate,
         Action<DataElement> dataProcessor) {
    //...
    DateElement element = //...
    if (predicate(element))
        dataProcessor(element);
    //...
} //TraverseData


Having, let's say two different algorithm for data traversal, two different predicates and two different data processors, without delegates to combine all 8 cases would have to write down 8 different versions of TraverseData, loosing all possible code reuse. That's why treating methods as first-class citizens (in the form of delegate instances) is so important.

For another interesting example, see my small article in Tips/Tricks section:
Hide Ad-hoc Methods Inside the Calling Method’s Body[^].

See also my other answer on the role of this: static functions[^]. It has nothing to do with delegates but provides some clarification on instance vs. static methods.

Further reading should probably needs understanding Closures: http://en.wikipedia.org/wiki/Closure_(computer_science)[^] and then lambda expressions, as they are understood in .NET: http://en.wikipedia.org/wiki/Functional_programming[^].

[EDIT]
For advanced use of delegates see my recent article: Dynamic Method Dispatcher[^]

and a short Tips/Trick article: Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

—SA
 
Share this answer
 
v7
Comments
Abhinav S 1-Feb-11 4:35am    
Super answer!
Sergey Alexandrovich Kryukov 30-May-11 11:50am    
Abhinav, please see my recent article on the topic: Dynamic Method Dispatcher, see updated answer above.
--SA
Abhinav S 30-May-11 12:40pm    
Saw it and gave my 5.
Sergey Alexandrovich Kryukov 30-May-11 15:22pm    
Thank you very much, Abhinav.
--SA
Dylan Morley 1-Feb-11 5:13am    
Excellent, very thorough - 5
One more point I want to add.

If you want to use LoadLibrary()/GetProcAddress() to use methods of .dll files you have use delegates.

It's one of the ways to connect C# codes to C++ codes.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 1-Feb-11 1:10am    
Good point - my 5. This is important practical aspect.
However, OP issue is rather not understanding delegates conceptual role.
--SA
Christy A C 1-Feb-11 4:42am    
Thanks
In the first case, you are writing code which cannot change at runtime.

With delegates, you can decide which method to call at runtime.
Thus delegates are one way to achieve late binding.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 1-Feb-11 0:35am    
Abhinav, your arguments are correct, but at level OP has at the moment, explanations are needed. I provided some -- what do you think?
--SA
Abhinav S 1-Feb-11 2:10am    
That was very very detailed. 5.
I preferred the brief and direct approach for my answer :).
Sergey Alexandrovich Kryukov 1-Feb-11 3:12am    
I'm sorry to disappoint you, but... everyone say I'm tough :-)

These short statements are not accurate enough. Let me explain. "writing code cannot change at runtime". You see, no code is ever changing during run-time. Even if you do late binding, nothing changes in code (and the code can be even be statically predicted).

"With delegates, you can decide which method to call at runtime." Again, no difference with delegate or without. Let's put brackets in your statement: During compilation time (it is defined what code is called during runtime). With or without delegate. If you have method1 and method2, at the line where you call them, you decide with one, same as with delegate.

Whatever you say, you will never see different effect before you pass a delegate as a method parameter (operator "+=" is also a call the the method with delegate as a parameter). This is a key, not runtime vs. compile time. Can you see the difference?

Short answer would be "because delegates are first-class citizens, class members are not -- RTFM".

Please, understand this. I do think it's useful.
Thank you very much for your attention to this matter.
Respect,
--SA
Abhinav S 1-Feb-11 9:31am    
Thanks for this information. :)
My attention is guaranteed.
Christy A C 1-Feb-11 4:35am    
Thanks so much for the respose, will you please post a simple code snippet to do the late binding
with delegate?
Delegates are very similar to 'pointers to functions' in C and C++

First we create a delegate, then we can assign any function that has a similar prototype of the one which we have specified with the delegate.

Declaration:

public delegate int Dlg(int x, int y); //where Dlg is the name of Delegate

Create Object:
when we need to create a 'Delegate object' (i.e. a pointer to a function which has a specified prototype)

Dlg d1=new Dlg(function_name); //if the class is in some other class use 'class_name.function_name'

function_name->has to be the name of a function which receives two integers as arguments and return an integer

Invoking function:

int res=d1(20, 20);

Cegonsoft
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900