开发者

Please show me a situtation which shows `need` for Delegates (or) function pointers

开发者 https://www.devze.com 2022-12-12 19:29 出处:网络
I\'m going take a class on \"Delegates and Callbacks\" to students who are learning level programmers. They have basic c/c++ & c# background. Instead of directly showing how to use them. I want to

I'm going take a class on "Delegates and Callbacks" to students who are learning level programmers. They have basic c/c++ & c# background. Instead of directly showing how to use them. I want to show "Why Function Pointers?" first. I want to start with an example situation and ask them "How will you do this"? and make them realize the need for something and then introduce them to FunctionPointers, Delegates &开发者_JS百科 CallBacks.

So, Can any one show me a good example which shows the need for Delegates in C# (or) function pointers in C/C++. I don't want example of event handling in GUI example and I don't want demonstration of "How to use delegates" with an examples of kind add2numbers etc..

I'm looking for something practical example where they could feel the need of FunctionPointers, Delegates & CallBacks.

If there are any good articles, please post them.


You can show them an example of filtering a list of items in several places in your software.

For example, you might have

public List<Person> GetMale(List<Person> people)
{
   List<Person> results = new List<Person>();
   foreach (Person p in people)
   {
       if (p.IsMale)
          results.Add(p);
   }
   return results;
}

or

public List<Person> GetFemale(List<Person> people)
{
   List<Person> results = new List<Person>();
   foreach (Person p in people)
   {
       if (!p.IsMale)
          results.Add(p);
   }
   return results;
}

To avoid repeating the foreach iteration in every method, you will want to extract the actual condition (i.e. a predicate in this case), and have it implemented somewhere else.

So you will replace these two methods with:

public List<Person> Filter(List<Person> people, Func<bool, Person> match)
{
   List<Person> results = new List<Person>();
   foreach (Person p in people)
   {
       if (match(p))
          results.Add(p);
   }
   return results;
}

and then call it in your code like this:

List<Person> malePersons = Filter(people, p => p.IsMale);
List<Person> femalePersons = Filter(people, p => !p.IsMale);

Note that the actual condition is now extracted outside of the iterating block, and you can reuse the same method to create any custom filtering logic you like. By extracting this logic, you are delegating the problem to someone else, making your code loosely coupled.

Using C# 2.0 anonymous method syntax, calling this method would look like this:

List<Person> malePersons = Filter(people, 
   delegate (Person p) { return p.IsMale; });
List<Person> femalePersons = Filter(people, 
   delegate (Person p) { return !p.IsMale; });

or using actual methods:

List<Person> malePersons = Filter(people, MaleMatch);
List<Person> femalePersons = Filter(people, FemaleMatch);

where predicates are defined as:

private bool MaleMatch(Person p)
{ 
   return p.IsMale;
}

private bool FemaleMatch(Person p)
{ 
   return !p.IsMale;
}

It is important to note that we are not passing the result of these methods, but actual method "pointers", so actual results will be returned when the method is called inside the Filter method.

Note also that LINQ in .Net 3.5 already contains a Where extension method which does the same thing like this example, and many other methods which use delegates for conditions, projecting and other stuff, so you basically only need to pass a delegate with the appropriate signature.


I'm not sure why you don't want to use a GUI example: the concept of "when I click a button, I want X to happen - now how to I express X?" is quite a good one.

Other examples:

  • I want to start a thread: how do I express what I want it to do?
  • I want to filter some data: how do I express the filter?
  • I want to project some data: how do I express the projection?
  • I want to download a file from the web asynchronously: how do I express what I want to happen when it's finished downloading?

Basically each of these is a case of saying, "I want to express some code in a simple way." In each case you could use a single method interface - delegates/function pointers are just a more convenient way of doing that.

Indeed, if some of the students are used to using single method interfaces (e.g. Runnable in Java) then that's probably a good starting point. Imagine if you could implement an interface by saying "just use this method over here..." (And in Java 7 it looks like you'll be able to do just that; they're using single method interfaces and method references in lieu of dedicated delegate types.) From a C# background you can also compare the IComparer<T> interface with the Comparer<T> delegate.

Of course when you've got the idea of delegates, you can then introduce lambda expressions (if it's a C# course) showing them how useful it is to be able to express that bit of logic "inline". Then show them how it's useful to be able to interact with the local environment, using lambdas as closures...


I would show how to write/use a generic sort function/method, which takes a callback parameter as a predicate.


Asyncrhonous calls: you call a method that will execute in background (usually a remote service call), and you want to specify which code will execute when the method finishes (since you indeed need to know when the method finishes). See here for more details: http://msdn.microsoft.com/en-us/magazine/cc301332.aspx


The Observer-Pattern is an example. The main reason for Callbacks/Delegates is, that you want to reduce coupling and increase flexibility of the architecture for further developments.


Delegates allow you to view code as data, so anytime you want something done in a certain way but leave the details to the caller delegates come in handy. Sorting is probably the prime example, but there are many others as illustrated by some of the answers.

E.g. let's say you want to time something. Since you basically want to go through the same timing steps no matter what you're timing, you can let your timing method take a delegate and time that in a consistent way. In pseudo code it could look something like this

TimeThis(method_pointer) {
   setup_timing();
   method_pointer(); // invoke the method
   report_timing();

}


Yet another example

Let's assume that you want to define a method that draws a curve for any function of the form f(x). First attempt

public DrawFunction(string f)
{
    for (int x = 0; x <= 10; x++) {
        DrawPoint( ??? ); // How are you calling f(x) here?
    }
}

Delegates are a mean of using methods as data. I.e. a variable or property or parameter of a delegate type can store a method. We can solve our problem using a delegate like this:

public DrawFunction(Func<double, double> f)
{
    for (int x = 0; x <= 10; x++) {
        DrawPoint(10.0 * x, f(x));
    }
}

Let's assume that we have defined this method

public double Square(double x) 
{
    return x * x;
}

Now you can draw the function like this

DrawFunction(Square);

Note that we do not call (execute) Square here, therfore we don't place braces () after Square.

We can also use lambda expressions instead. We obtain the same result with

DrawFunction(x => x*x);

Another curve

DrawFunction(x => 1.0/(1.0 + x*x));


You can take the example of how events are implemented in .NET; your students can easily relate to it.


To Jon Skeet. Yes, every delegate may be represented as single-method interface, but you may not implement different versions of it in one class. With delegates (function pointers) you may have as many implementations as you want - different names but same signature:

class C
{
  int Add(int a, int b)
  {
    return a + b;
  }
  int Mul(int a, int b)
  {
    return a * b;
  }
};

But you cannot implement the same interface twice (see my class C above). For C++ and C# although we can emulate delegates with interfaces. But for C in is necessary intrument to make callback and runtime polymorphism. In C++ and C# it much for compaitibility and convience.


namespace WindowsApplication10
{
    /// <summary>
    /// This delegate will be used by the button 
    /// </summary>
    public delegate Point GetCenter();

    public partial class Form1 : Form
    {
        CentralButton central;
        public Form1()
        {
            InitializeComponent();
            central = new CentralButton(this.GetCenter);
            this.Controls.Add(central);
        }

        public Point GetCenter() 
        {
            return new Point(this.Width / 2, this.Height / 2);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            central.UpdateCenter();
        }
    }

    /// <summary>
    /// This button calculates its location in the center of the parent
    /// </summary>
    public class CentralButton : Button 
    {
        GetCenter myGetCenterMethod;
        public CentralButton(GetCenter findCenterMethod)
        {
            myGetCenterMethod = findCenterMethod;
        }

        public void UpdateCenter()
        {
            // use the delegate for obtain the external information
            this.Location = myGetCenterMethod();
        }
    }
}


Checkout the Can your programming language do this? article from Joel.

He has few good examples where there are two functions that are almost doing the same thing, but use different functions to achieve a certain task.

alert("get the lobster");
PutInPot("lobster");
PutInPot("water");

alert("get the chicken");
BoomBoom("chicken");
BoomBoom("coconut");

Refactored with functions passed as arguments:

function Cook( i1, i2, f )
{
    alert("get the " + i1);
    f(i1);
    f(i2);
}

Cook( "lobster", "water", PutInPot );
Cook( "chicken", "coconut", BoomBoom );
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号