Possible Duplicates:
When would you use delegates in C#? The purpose of delegates
I have seen many question regarding the use of delegates. I am still not clear where and WHY would you use delegates instead of calling the method directly.
I have heard this phrase many times: "The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked."
I don't understand how that statement is correct.
I've written the following examples. Let's say you have 3 methods with same parameters:
public int add(int x, int y)
{
int total;
return total = x + y;
}
public int multiply(int x, int y)
{
int total;
return total = x * y;
}
public int subtract(int x, int y)
{
int total;
return total = x - y;
}
Now I declare a delegate:
public delegate int Operations(int x, int y);
Now I can take it a step further a declare a handler to use this delegate (or your delegate directly)
Call delegate:
MyClass f = new MyClass();
Operations p = new Operations(f.multiply);
p.Invoke(5, 5);
or call with handler
f.OperationsHandler = f.multiply;
//just displaying result to text as an example
textBoxDelegate.Text = f.OperationsHandler.Invoke(5, 5).ToString();
In these both cases, I see my "multiply" method being specified. Why do people use the phrase "change functionality at runtime" or the one above?
Why are delegates used if every time I declare a delegate, it needs a method to point to? and if it needs a method to point to, why not just call that method directly? It seems to me that I have to write more code to use 开发者_C百科delegates than just to use the functions directly.
Can someone please give me a real world situation? I am totally confused.
Changing functionality at runtime is not what delegates accomplish.
Basically, delegates save you a crapload of typing.
For instance:
class Person
{
public string Name { get; }
public int Age { get; }
public double Height { get; }
public double Weight { get; }
}
IEnumerable<Person> people = GetPeople();
var orderedByName = people.OrderBy(p => p.Name);
var orderedByAge = people.OrderBy(p => p.Age);
var orderedByHeight = people.OrderBy(p => p.Height);
var orderedByWeight = people.OrderBy(p => p.Weight);
In the above code, the p => p.Name
, p => p.Age
, etc. are all lambda expressions that evaluate to Func<Person, T>
delegates (where T
is string
, int
, double
, and double
, respectively).
Now let's consider how we could've achieved the above without delegates. Instead of having the OrderBy
method take a delegate parameter, we would have to forsake genericity and define these methods:
public static IEnumerable<Person> OrderByName(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByAge(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByHeight(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByWeight(this IEnumerable<Person> people);
This would totally suck. I mean, firstly, the code has become infinitely less reusable as it only applies to collections of the Person
type. Additionally, we need to copy and paste the very same code four times, changing only 1 or 2 lines in each copy (where the relevant property of Person
is referenced -- otherwise it would all look the same)! This would quickly become an unmaintainable mess.
So delegates allow you to make your code more reusable and more maintainable by abstracting away certain behaviors within code that can be switched in and out.
.NET Delegates: A C# Bedtime Story
Delegates are extremely useful, especially after the introduction of linq and closures.
A good example is the 'Where' function, one of the standard linq methods. 'Where' takes a list and a filter, and returns a list of the items matching the filter. (The filter argument is a delegate which takes a T and returns a boolean.)
Because it uses a delegate to specify the filter, the Where function is extremely flexible. You don't need different Where functions to filter odd numbers and prime numbers, for example. The calling syntax is also very concise, which would not be the case if you used an interface or an abstract class.
More concretely, Where taking a delegate means you can write this:
var result = list.Where(x => x != null);
...
instead of this:
var result = new List<T>();
foreach (var e in list)
if (e != null)
result.add(e)
...
Why are delegates used if everytime I declare a delegate, it needs a method to point to? and if it needs a method to point to, why not just call that method directly?
Like interfaces, delegates let you decouple and generalize your code. You usually use delegates when you don't know in advance which methods you will want to execute - when you only know that you'll want to execute something that matches a certain signature.
For example, consider a timer class that will execute some method at regular intervals:
public delegate void SimpleAction();
public class Timer {
public Timer(int secondsBetweenActions, SimpleAction simpleAction) {}
}
You can plug anything into that timer, so you can use it in any other project or applications without trying to predict how you'll use it and without limiting its use to a small handful of scenarios that you're thinking of right now.
Let me offer an example. If your class exposes an event
, it can be assigned some number of delegates at runtime, which will be called to signal that something happened. When you wrote the class, you had no idea what delegates it would wind up running. Instead, this is determined by whoever uses your class.
One example where a delegate
is needed is when you have to modify a control in the UI thread and you are operating in a different thread. For example,
public delegate void UpdateTextBox(string data);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
...
Invoke(new UpdateTextBox(textBoxData), data);
...
}
private void textBoxData(string data)
{
textBox1.Text += data;
}
In your example, once you've assigned a delegate to a variable, you can pass it around like any other variable. You can create a method accepting a delegate as a parameter, and it can invoke the delegate without needing to know where the method is really declared.
private int DoSomeOperation( Operations operation )
{
return operation.Invoke(5,5);
}
...
MyClass f = new MyClass();
Operations p = new Operations(f.multiply);
int result = DoSomeOperation( p );
Delegates make methods into things that you can pass around in the same way as an int. You could say that variables don't give you anything extra because in
int i = 5;
Console.Write( i + 10 );
you see the value 5 being specified, so you might as well just say Console.Write( 5 + 10 )
. It's true in that case, but it misses the benefits for being able to say
DateTime nextWeek = DateTime.Now.AddDays(7);
instead of having to define a specifc DateTime.AddSevenDays()
method, and an AddSixDays
method, and so on.
To give a concrete example, a particularly recent use of a delegate for me was SendAsync()
on System.Net.Mail.SmtpClient
. I have an application that sends tons and tons of email and there was a noticeable performance hit waiting for the Exchange server to accept the message. However, it was necessary to log the result of the interaction with that server.
So I wrote a delegate method to handle that logging and passed it to SendAsync()
(we were previously just using Send()
) when sending each email. That way it can call back to the delegate to log the result and the application threads aren't waiting for the interaction to finish before continuing.
The same can be true of any external IO where you want the application to continue without waiting for the interaction to complete. Proxy classes for web services, etc. take advantage of this.
You can use delegates to implement subscriptions and eventHandlers. You can also (in a terrible way) use them to get around circular dependencies.
Or if you have a calculation engine and there are many possible calculations, then you can use a parameter delegate instead of many different function calls for your engine.
Did you read http://msdn.microsoft.com/en-us/library/ms173171(VS.80).aspx ?
Using your example of Operations
, imagine a calculator which has several buttons.
You could create a class for your button like this
class CalcButton extends Button {
Operations myOp;
public CalcButton(Operations op) {
this.myOp=op;
}
public void OnClick(Event e) {
setA( this.myOp(getA(), getB()) ); // perform the operation
}
}
and then when you create buttons, you could create each with a different operation
CalcButton addButton = new CalcButton(new Operations(f.multiply));
This is better for several reasons. You don't replicate the code in the buttons, they are generic. You could have multiple buttons that all have the same operation, for example on different panels or menus. You could change the operation associated with a button on the fly.
Delegates are used to solve an Access issue. When ever you want to have object foo that needs to call object bar's frob method but does not access to to frob method.
Object goo does have access to both foo and bar so it can tie it together using delegates. Typically bar and goo are often the same object.
For example a Button class typically doesn't have any access to the class defines a Button_click method.
So now that we have that we can use it for a whole lot things other than just events. Asynch patterns and Linq are two examples.
It seems many of the answers have to do with inline delegates, which in my opinion are easier to make sense of than what I'll call "classic delegates."
Below is my example of how delegates allow a consuming class to change or augment behaviour (by effectively adding "hooks" so a consumer can do things before or after a critical action and/or prevent that behaviour altogether). Notice that all of the decision-making logic is provided from outside the StringSaver
class. Now consider that there may be 4 different consumers of this class -- each of them can implement their own Verification
and Notification
logic, or none, as appropriate.
internal class StringSaver
{
public void Save()
{
if(BeforeSave != null)
{
var shouldProceed = BeforeSave(thingsToSave);
if(!shouldProceed) return;
}
BeforeSave(thingsToSave);
// do the save
if (AfterSave != null) AfterSave();
}
IList<string> thingsToSave;
public void Add(string thing) { thingsToSave.Add(thing); }
public Verification BeforeSave;
public Notification AfterSave;
}
public delegate bool Verification(IEnumerable<string> thingsBeingSaved);
public delegate void Notification();
public class SomeUtility
{
public void SaveSomeStrings(params string[] strings)
{
var saver = new StringSaver
{
BeforeSave = ValidateStrings,
AfterSave = ReportSuccess
};
foreach (var s in strings) saver.Add(s);
saver.Save();
}
bool ValidateStrings(IEnumerable<string> strings)
{
return !strings.Any(s => s.Contains("RESTRICTED"));
}
void ReportSuccess()
{
Console.WriteLine("Saved successfully");
}
}
I guess the point is that the method to which the delegate points is not necessarily in the class exposing the delegate member.
精彩评论