Let's talk about entrusting those things, and talk about entrusting things.
Dig for delegated tasks, anonymous methods, commissioned inverter and covariant, delegate and closure, C # self-executed Functions
What is the basic commission?
Many people think that "function pointer" is a delegated instance.
The delegate definition is similar to interface, which is a "standard" or "template" of a method to regulate the "behavior" of a method, so that the method can be passed as a parameter.
Public delegate void MyDelegate ();
In this way, a delegate with no parameter and no return value is defined, and the instance of this delegate must be a method without parameter and no return value.
Public class MyClass {public static void MyMethod1 (){}
Public static void MyMethod2 (){}}
MyDelegate myDelegate = new MyDelegate (MyClass. myMethod1); // defines the delegated instance and adds the corresponding operation method // MyDelegate myDelegate = MyClass. myMethod; // <-- the abbreviation is myDelegate + = MyClass. myMethod2; // multicast delegate
The code above demonstrates the basic usage of delegation. You can also use the Delegate. Combin () method to implement multicast delegation.
Multicast delegation can be beautified into the following code
MyDelegate myDelegate = null;myDelegate += MyClass.MyMethod1;myDelegate += MyClass.MyMethod2;
Is it much more beautiful!
After C #3, common delegates can be replaced by Action and Func (C #3 or 2 forget --)
Significance of delegate: Method Transfer
Real case:
The custom base class of controller has a protected void CreateCookie (string name, string value) method.
After obtaining the openid, perform some database processing and save the login information of this openid to cookies.
public static void SetOpenId(string openId, Action<string, string> setCookie)
WeixinTool.SetOpenId(openid, CreateCookie);
In this way, the CreateCookie is passed to the SetOpenId method.
Anonymous Method
You do not need to define the method name. directly write the method body and assign it to the delegate.
Lambda expressions are not used much after they are generated. Actually, lambda expressions are anonymous methods.
MyDelegate anonymous1 = delegate () {Console. writeLine ("this is a test 1") ;}; // anonymous method MyDelegate anonymous2 = () =>{ Console. writeLine ("this is a test 2") ;}; // lambda expression anonymous1 (); anonymous2 ();
After the above Code is compiled, using IlSpy to view the code is directly two anonymous delegates.
Using ildasm to view il is also consistent
Said the delegate, should it be the event?
You should have written about winform. click the button to trigger the click event. The event handler affects the event.
Everyone knows that there are events, but they cannot accurately describe what the events are (whether the optimized version of the multicast delegate mentioned above looks like an event)
public event MyDelegate ChangeSomething;
First, the event is "attribute", which is a "attribute" of the class. Therefore, it can only be defined in one class (or struct)
However, the event keyword prevents you from directly assigning values to this attribute, so you can only use "+ =" or "-=" to operate this "attribute"
The purpose of an event is to implement the "Publish/subscribe mode", that is, pub/sub
Why can't you assign values to this attribute directly? Because "subscriber" does not know how many people subscribe to this event. If everyone uses "=" for operations, the subsequent "subscriber" will overwrite the previous "subscriber", which may easily cause bugs. Therefore, the event keyword encapsulates the delegate and closes the direct value assignment channel.
Commissioned inverter and covariant
Many people who have used generics know that generics have inverters and coincidences. In fact, delegates also have inverters and coincidences (interfaces and arrays also have this feature)
So what is inverter and covariant?
To put it simply
Inverter:
The base class is changed to the subclass-> it is a day, and this is all possible, so it is called an inverter.
The inverter is actually compiled only when the compiler infer that the type can be converted based on the execution context.
It seems that the "is-a" link is actually converted to a normal one.
Covariant:
Subclass-> CLR assists in deformation, so it is called covariant.
We often use the "is-a" relationship in programming, so it can be converted normally.
For delegation, the inverter and the covariant can be a change in the return value, parameter, or both.
Let's look at some specific Chestnuts:
Define types and inheritance
class Person {} class Employee : Person {}
Define Delegation
delegate Person EmployeeInPersonOut(Employee employee);
Define methods suitable for Delegation
class Methods{ public static Person EmployeeInPersonOut(Employee employee) { return new Person(); } public static Employee EmployeeInEmployeeOut(Employee employee) { return new Employee(); } public static Person PersonInPersonOout(Person person) { return new Person(); } public static Employee PersonInEmployeeOut(Person person) { return new Employee(); }}
General Use
// General use of EmployeeInPersonOut employeeInPersonOut = Methods. EmployeeInPersonOut; Person person = employeeInPersonOut (new Employee ());
Covariant
// Covariant usage/** the returned value of "is-a" relationship between Employee and Person. Therefore, it is a regular conversion */EmployeeInPersonOut employeeInPersonOut = Methods. employeeInEmployeeOut; Person person = employeeInPersonOut (new Employee ());
Inverter
// Inverter usage/** for the delegate statement: the delegate method parameter Person can be changed to Employee! * The Compiler inferred from the context that the object can be converted successfully. * during execution, the delegate declaration EmployeeInPersonOut can only be input into the Employee * Employee for Methods. the peron parameter of PersonInPersonOout is "is-a relation", so it can be converted to the method parameter */EmployeeInPersonOut employeeInPersonOut = Methods. personInPersonOout; Person person = employeeInPersonOut (new Employee ());
Used Together with Inverter
// This section will not be explained. You can see the principles of the first two sections: EmployeeInPersonOut employeeInPersonOut = Methods. PersonInEmployeeOut; Person person = employeeInPersonOut (new Employee ());
Application of covariant in winform
class Program{ static void Main(string[] args) { var button = new Button(){Text = "click me!"}; button.Click += HandleEvent; button.KeyPress += HandleEvent; var form = new Form(); form.Controls.Add(button); Application.Run(form); } static void HandleEvent(object sender, EventArgs args) { MessageBox.Show(args.GetType().FullName); }}
It is also possible to ignore event parameters using anonymous parameter-free delegation.
button.Click += delegate {/*do something.*/};
Delegate and closure What is a closure
class Program{ static void Main(string[] args) { var action = ClosureMethod(); action(); action(); action(); Console.ReadKey(); } static Action ClosureMethod() { int localCounter = 0; Action x = delegate { localCounter++; Console.WriteLine(localCounter); }; return x; }}
This code output 1, 2, 3 in sequence
This is the closure.
You can refer to the closure in javascript to guess: the anonymous method uses the local variable "localCounter", so that the variable cannot be released after the method is executed, thus forming a "global variable within the scope"
Let's verify this guess.
Sacrifice artifact: IL DASM
To make it simple, I made some modifications to the code.
Static Action ClosureMethod () {string local = "zero"; Action x = delegate {local + = ""; Console. WriteLine (local) ;}; return x ;}
Chinese characters are easier to locate in il
From il, we can see that
C # the closure is not the same as js because of the garbage collection mechanism.
The anonymous method captures the local variable "local" of an "external method"
Make the compiler generate an "internal class" (<> c_DisplayClass1)
The "external method" directly uses the variables in this "internal class" instance (<> c_DisplayClass1: local in il)
The instance is also used by the delegate "Aciton x"
This completes the closure, so the closure in C # is fully the responsibility of the compiler.
The function of the closure 1. Local variable instantiation, so that the external can use this variable
static IList<string> StringFilter(List<string> list, int length) { return list.FindAll(delegate(string str) { return str.Length > length; }); }
You can also use lambda expressions.
static IList<string> StringFilter(List<string> list, int length) { return list.FindAll(str => str.Length > length); }
Previously, lambda expressions are actually anonymous methods.
The above code captures the length of the external variable.
2. extend the life cycle of a variable, the Delegate does not die, and the variable does not die (var action = ClosureMethod (); this variable "local" of "ClosureMethod" will be released after the action is released)
Just like the counter of the first code in the closure section, after the "ClosureMethod" method is executed, the lifecycle of the variable "localCounter" is extended.
Let's talk about the pitfalls in closures.
Use closures in
Pit 1:
static void Main(string[] args){ var actions = LoopClosure(); actions[0](); actions[0](); actions[0](); actions[1](); actions[2](); Console.ReadKey(); } static IList<Action> LoopClosure(){ var list = new List<Action>(); for (int i = 0; i < 3; i++) { int val = i*10; list.Add(delegate { val++; Console.WriteLine(val); }); } return list;}
The output result is 1, 2, 3, 11, and 21.
This loop generates only one "internal class", but each cycle generates an "internal class" instance.
Pit 2:
var actions = new List<Action>();for (int i = 0; i < 3; i++) actions.Add(() => Console.WriteLine(i));//access to modified closure 'i'foreach (var action in actions) action();
The output result is 3, 3.
Because the changed/modified closure variables are used
But there is no such pitfall in foreach.
var actions = Enumerable.Range(0, 3).Select(i => (Action)(() => Console.WriteLine(i))).ToList();
In this way, the closure in foreach can normally output 0, 1, 2
Interesting programming: Can I write a self-execution method in C # Like javascript? The answer is obviously correct.
// Self-execution without Parameters
(Action) (delegate
{
Console. WriteLine ("I'm a IIFE method .");
}))();
// Self-execution with Parameters
(Action <int>) (delegate (int I ){
Console. WriteLine ("I'm a IIFE method with parameter: {0}", I );
}) (2 );
References:
Https://msdn.microsoft.com/zh-cn/library/ee207183.aspx
Https://msdn.microsoft.com/zh-cn/library/dd233060.aspx
Https://msdn.microsoft.com/zh-cn/library/dd465122.aspx
Http://csharpindepth.com/articles/chapter5/closures.aspx
You are welcome to repost this article in any form.
Reprinted Please note: Article Reprinted from: blog park [http://www.cnblogs.com]
Title: about entrusting
Address: http://www.cnblogs.com/eyu/p/all_those_delegate_things.html