Objective
Occasionally flipping through the books to see the original rational things are really a bit dull, before you see a park in the garden friends said 3-6 years of work experience should be understood. NET knowledge, one point is about the closure in C #, in fact, early in the book (before I did not know that there is a closure in C #) to see the content of the closure is very small and the introduction of the example of a look to understand (finally, there is an impression), anyway, work and do not come to let you to achieve closure, So oneself have the luck psychology, this two days whim again turned over the book want to study carefully (perhaps out of the fear of it, work a few years unexpectedly do not know the closure, even if know and only to understand, you are self-deceiving), immediately after the study of the information to research this thing, if there are errors, please point out.
Topic
First of all, let's look at the evolutionary evolution of the Commission, and it is asked that the topic in this section is not "C # The thought of closures caused by variable capture"? Oh, look also carefully, yes, we can not worry about it, and someone asked, you did not write about the delegation of the detailed introduction, oh, it seems that my fans know a lot, but this introduction focus on different, nonsense less, into the theme is the truth.
The delegate of c#1.0
We know it today. A list can be implemented by lamda such as where or predicate, whereas in c#1.0 we have to write a method to implement the predicate logic, and the creation of the delegate instance is created by the specified method name. Let's create a helper Class (Listutil), as follows:
<summary>/// operation List Help class/// </summary> static class Listutil {// <summary > ///Create a predicate ///</summary> public static ilist<t> filter<t> (ilist<t> SOURCE, predicate<t> predicate) { list<t> ret = new list<t> (); foreach (T item in Source) { if (predicate (item)) { ret. ADD (item); } } return ret; } <summary> ///traverse the list and print on the console ///</summary> public static void Dump<t> (IList <T> list) { foreach (T item in list) { Console.WriteLine (item); } Console.readkey (); } }
At the same time, a test data is given:
Static class SampleData {public static readonly ilist<string> Words = new List<string> {"The", "Quick", "Brown", "Fox", "jumped", "over", "the", "lazy", "dog"}. AsReadOnly (); }
Now all we have to do is return a string with a small length equal to 4 and print it, giving a method with a length less than 4:
static bool Matchfourlettersorfewer (string item) { return item. Length <= 4; }
Here we call the above method in the console to filter:
predicate<string> predicate = new predicate<string> (matchfourlettersorfewer); ilist<string> shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords);
The results are printed as follows:
All of the above are so easy! when we use delegates to implement a simple one-time call is not used many times, in order to streamline the code, the anonymous method appears in C # 2.0.
The delegate of c#2.0
The above method of calling in the console can be modified to achieve the same effect as follows:
predicate<string> predicate = Delegate (string item) { return item. Length <= 4; }; ilist<string> shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords);
Well, here seems a bit of a waste of space, to here we look at the above code, for predicate the length of the filter data is hard-coded, missing something, we first want to talk about the closure, What is needed for closures can be summarized as: Closures are entities that combine functions with their referencing environment (from: What you have to know.) NET). We can interpret it as a synthesis of functions and contexts. We need to give a context by manually entering the length of the filtered data. We give a filter-length class (Variablelengthmather):
public class Variablelengthmatcher { int maxLength; <summary>///// transfer of data entered manually///</summary>// <param name= "MaxLength" ></param > Public variablelengthmatcher (int maxLength) { this.maxlength = maxLength; } <summary> ///similar to anonymous method ///</summary> public bool Match (string item) { return item. Length <= maxLength; } }
Let's do a manual input call to filter the data:
Console.Write ("Maximum length of string to include?"); int maxLength = Int. Parse (Console.ReadLine ()); Variablelengthmatcher matcher = new Variablelengthmatcher (maxLength); predicate<string> predicate = Matcher. Match; ilist<string> shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords);
The demo is as follows:
We then make the following modifications to the console code:
Console.Write ("Maximum length of string to include?"); int maxLength = Int. Parse (Console.ReadLine ()); Variablelengthmatcher matcher = new Variablelengthmatcher (maxLength); predicate<string> predicate = Matcher. Match; ilist<string> shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords); Console.WriteLine ("Now for Words with <= 5 letters:"); MaxLength = 5; Shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords);
We just changed the MaxLength value and printed it again, and the results were as follows:
The delegate of c#3.0
For a better demonstration of the code, we use the LAMDA expression in c#3.0 to demonstrate, we continue to the above, when we change maxlength to 5 o'clock, when we filter the data and 4, at this time we use the anonymous method or the LAMDA expression as shown above, as shown below.
Console.Write ("Maximum length of string to include?"); int maxLength = Int. Parse (Console.ReadLine ()); predicate<string> predicate = Item and item. Length <= maxLength; ilist<string> shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords); Console.WriteLine ("Now for Words with <= 5 letters:"); MaxLength = 5; Shortwords = Listutil.filter (sampledata.words, predicate); Listutil.dump (shortwords);
Look at the demo results:
From the above demonstration results can be seen at this time the MaxLength is 5, of course, the results of print filtering is not the same, this time to talk about the first topic "Variable Capture." Both anonymous methods and lambda expressions in C # 2.0 and 3.0 can capture local variables.
So the question is, what is variable capture? How do we understand it?
Let's look at another example using lambda expressions:
var name = "Cnblogs"; func<string> capture = () = name; Name = "xpy0928"; Print (Capture);
static void Print (Func<string> capture) { Console.WriteLine (Capture ()); Console.readkey (); }
So what will the printing result be? Cnblogs? xpy0928?
Name is captured, and the lambda also makes a corresponding change when the local variable changes (because lambda delays execution), so the xpy0928 is output. So what exactly does the compiler do to make the output xpy0928? Inside the compiler, the above code is converted roughly as follows.
public class Capture {public string name; public string Printname () { return this.name; } }
var capture = new Capture (); Capture.name = "Cnblogs"; Capture.name = "xpy0928"; Print (Capture.printname);
When we get here, we can understand the meaning of capturing variables. The lambda always points to the name value in the current object, that is, the reference in the object always exists in Lamda.
The next thing to say about closures is that we've been talking about variable capture before, because the source of the closure is the variable capture. (Personal understanding, if there are errors please correct).
The result of a variable capture is that the compiler produces an object and promotes the local variable to an instance variable to extend the life cycle of the local variable, which is called a closure.
What is the meaning of the above remark? Let's look at one more example:
List<func<int>> Funcs = new list<func<int>> (); for (int j = 0; J <; J + +) Funcs. ADD (() = j); foreach (func<int> func in Funcs) Console.WriteLine (func ()); Console.readkey ();
Some people say the above example is a closure, yes, a closure and the result returns 10 10, well done! That's not it, we have to explain it. Let's look at it in a sentence.
Funcs. ADD (() = j);
() What does =>j mean, let's take a look at the six evolution of the lambda expression before:
Instantiate an anonymous delegate and return the J value, note that () =>j is the current value of the return variable J rather than the return value J. The returned anonymous delegate is an anonymous class and accesses the attribute in this class J (why is the returned anonymous delegate an anonymous class, see this link: http://www.cnblogs.com/jujusharp/archive/2011/08/04/ c-sharp-and-closure.html). After that, let's explain why we're printing 10 of 10?
Each anonymous delegate created now captures this variable J, so each anonymous delegate, the anonymous class, keeps a reference to the field J, and when the For loop finishes 10 o'clock the field value becomes 10 until J is not referenced by the anonymous delegate, and J is recycled by the garbage collector.
Let's take a look at the changes above:
List<func<int>> Funcs = new list<func<int>> (); for (int j = 0; J <; J + +) { int tempj = j; Funcs. ADD (() = TEMPJ); } foreach (func<int> func in Funcs) Console.WriteLine (func ()); Console.readkey ();
It is obvious that the output is 0-9 because a temporary variable, TEMPJ, is created at this point, and the anonymous delegate, which is the lambda captures a different tempj each iteration, can then be output as we expect.
Let's look at one more situation:
for (int j = 0; J <; J + +) { func<int> fun = () = j; Console.WriteLine (Fun ()); }
This is still normal output 0-9, because at this point the lambda expression executes immediately after each iteration, instead of all lambda executions, as in the case of the first example until the loop is deferred until 10.
Summarize
Closure concept: Closures allow you to encapsulate some behavior, pass it like an object, and still be able to access the context of the original declaration at the first time. This allows the control structure, logical operations, and so on to be separated from the invocation details.
Role: (1) facilitates code simplification. (2) facilitates function programming. (3) code security.
Resources:
C # in Depth:http://csharpindepth.com/articles/chapter5/closures.aspx
Variable Capture in C # with Anonymous delegates:http://www.digitallycreated.net/blog/34/variable-capture-in-c%23- With-anonymous-delegates
Understanding Variable Capturing in c#:https://blogs.msdn.microsoft.com/matt/2008/03/01/ understanding-variable-capturing-in-c/
C # and closures: http://www.cnblogs.com/jujusharp/archive/2011/08/04/C-Sharp-And-Closure.html
C # is caused by a variable capture of the closure