Visual C # 2.0 anonymous method uncover

Source: Internet
Author: User
Tags filter foreach anonymous define definition bool instance method variables
Visual Anonymous Method Basics

The anonymous method is a new language feature of the c#2.0. The main content of this article is to provide readers with a better understanding of the internal implementation and working methods of anonymous methods. This article is not intended to be a complete language attribute reference for anonymous methods.

Anonymous methods allow us to define blocks of code that the delegate object can accept. This feature eliminates an extra step when we create a delegate and want to pass it to a small block of code for a delegate. It also eliminates the confusion of small and medium-class code methods. Let's take a look: for example, we have a string set named MyCollection. This class has a method that obtains all the items in the collection that meet the filter criteria provided by the user, and the caller determines whether a particular item in the collection is eligible and is retrieved as part of the return array from this method.

public class mycollection
{
Public delegate bool SelectItem (string sitem);
Public string[] Getfiltereditemarray (SelectItem itemfilter)
{
list<string> slist = new list<string> ();
foreach (String sitem in M_slist)
{
if (Itemfilter (sitem) = = True) Slist.add (Sitem);
}
return Slist.toarray ();
}

Public list<string> ItemList
{
Get
{
return m_slist;
}
}
Private list<string> m_slist = new list<string> ();
}
We can write the code shown below using the class defined above:

public class Program
{
public static void Main (string[] args)
{
mycollection Objmycol = new mycollection ();
OBJMYCOL.ITEMLIST.ADD ("Aditya");
OBJMYCOL.ITEMLIST.ADD ("Tanu");
OBJMYCOL.ITEMLIST.ADD ("Manoj");
OBJMYCOL.ITEMLIST.ADD ("Ahan");
OBJMYCOL.ITEMLIST.ADD ("Hasi");

Gets an array of character entries in the collection that begin with the letter ' A '
string[] astrings = Objmycol.getfiltereditemarray (Filterstringwitha);
Console.WriteLine ("-----Strings starting with letter ' A '-----");
foreach (string s in astrings)
{
Console.WriteLine (s);
}
Gets an array of character entries in the collection that begin with the letter ' T '
string[] TStrings = Objmycol.getfiltereditemarray (FILTERSTRINGWITHT);
Console.WriteLine ("-----Strings starting with letter ' T '-----");
foreach (string s in TStrings)
{
Console.WriteLine (s);
}
}

public static bool Filterstringwitha (string sitem)
{
if (sitem[0] = = ' A ')
return true;
Else
return false;
}
public static bool Filterstringwitht (string sitem)
{
if (sitem[0] = = ' T ')
return true;
Else
return false;
}
}
We can see that for each of the simple filtering guidelines we want to provide, we should define a method (static or instance). This quickly confuses the code of the class. With anonymous methods, the code becomes quite natural. Here's how this program class is rewritten with an anonymous method:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
mycollection Objmycol = new mycollection ();
OBJMYCOL.ITEMLIST.ADD ("Aditya");
OBJMYCOL.ITEMLIST.ADD ("Tanu");
OBJMYCOL.ITEMLIST.ADD ("Manoj");
OBJMYCOL.ITEMLIST.ADD ("Ahan");
OBJMYCOL.ITEMLIST.ADD ("Hasi");
Gets an array of character entries in the collection that begin with the letter ' A '
string[] astrings = Objmycol.getfiltereditemarray (delegate (String sitem)
{
if (sitem[0] = = ' A ')
return true;
Else
return false;
});
Console.WriteLine ("-----Strings starting with letter ' A '-----");
foreach (string s in astrings)
{
Console.WriteLine (s);
//Gets an array of character entries in the collection that begin with the letter ' T '
string[] TStrings = Objmycol.getfiltereditemarray (delegate (String sitem)
{
if (sitem[0] = = ' T ')
return true;
Else
return false;
});
Console.WriteLine ("-----Strings starting with letter ' T '-----");
foreach (string s in TStrings)
{
Console.WriteLine (s);
}
}
}


As shown in the example above, we have been able to define a new method to represent each filter criterion, using the filter criteria defined by the inline code block. To be honest, using this inline code may seem natural and avoids defining a new method, but if the technique is used for larger inline blocks, the code quickly becomes unmanageable and can cause code duplication. Therefore, both the use method and the inline anonymous method are optional scenarios for the delegate/event processor.

Well, these are the basics of anonymous methods. The remainder of this article will discuss how the anonymous methods work within different scenarios. Understanding how anonymous methods are implemented and how they work internally is important for proper use of them. Otherwise, the results of your code using the anonymous method will look unpredictable.

  Usage of static data members for anonymous methods

Anonymous methods always start with a delegate keyword followed by the parameters used in the method and method body itself. As you can see from the example above, the user does not need to determine the return type of the anonymous method. It is inferred from the return statement in the body of the method. The. NET CLR cannot execute free flow (flowing) code blocks like anonymous methods. CLR requirements: Each method that it executes is part of a type and should be a static (static) method or an instance (instance) method: If a method declaration contains a static modifier, the method is called a static method. If there is no static modifier, the method is called an instance method. A static method does not operate on a particular instance, and referencing this in a static method is a compile-time error. An instance method operates on a given instance of a class, and can use this to access the instance. So when you write an anonymous method in the code of a class and compile the code, the C # compiler silently creates a static or instance method in the same class that you define the anonymous method. So the anonymous method is simply a convenient syntax for defining your own methods in a class to pass to a delegate (a delegate processor/event handler).

When you compile the example above, the C # compiler creates two private static methods inside the class ' program ' where we define anonymous methods. It replaces the anonymous method with the address of these static methods at this time. The compiler determines how to create a static method or an instance method depending on the use of static or instance data members in the class that the anonymous method is defined in. In our example, we didn't use any of the class ' program ' data members because calling a static method instead of an instance method would be efficient, so the C # compiler creates a static method that encapsulates the code for our anonymous method. The following is the ILDASM view of the sample assembly ' program ' class. The highlighted section shows a new static method added silently to the ' program ' class by the C # compiler.


If we have used any static data for the ' program ' class with anonymous methods, the C # compiler will still create a static method in the ' Program ' class to wrap the anonymous method.

   instance data member usage for anonymous methods

Let's define a new instance method in the ' program ' class in our example and use the example class (The ' program ' Class) as an instance data member. The following code shows the modified example:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
Instance data member test
Program P = new program ();
for (int i=1;i<=5;i++)
P.testinstancedatamembers ();
}
public void Testinstancedatamembers ()
{
MyDelegate d = Delegate
{
Console.WriteLine ("Count: {0}", ++m_icount);
};
D ();
}
public int m_icount = 0;
}
We define a new instance method: Testinstancedatamembers, which defines an anonymous method in the ' Program ' class, where the anonymous method uses the instance data member: The M_icount of the ' Program ' class. When this example is compiled, the C # compiler creates a private instance method to wrap the anonymous method defined in Testinstancedatamembers. The C # compiler must create an instance method because the method requires access to instance data members of the ' Program ' class. The following is the ILDASM view of the sample assembly ' program ' class. The lower section of the diagram shows a new private instance method silently added by the C # compiler to the ' Program ' class.

   local variable usage of anonymous methods

So far, we have a little basic understanding of how anonymous methods work and how they are implemented internally. Basically, C # creates a private method to wrap an anonymous method. The signatures of these methods also match the delegates to which they are assigned. Now, let's take a look at the following code:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
int itemp = 100;
MyDelegate dlg = Delegate
{
Console.WriteLine (ITEMP);
};
Dlg ();
}
}
This code should not be compiled for what we have learned so far about anonymous methods. Because we don't use instance data members, the C # compiler should create a private static method in the ' Program ' class to wrap this anonymous method. But how does the new method access local variables? This makes us believe that the code will not be compiled. But surprisingly, the C # compiler successfully compiled the code without any errors or alarms. Also, when you execute the example, the correct value for the ITEMP variable is printed on the console screen. Now let's go to the advanced topic of anonymous methods. An anonymous method has the ability to encapsulate the value of an environment variable that is used in its method body. This wrapper applies to all local variables in the method defined by the anonymous method. When the C # compiler recognizes the use of a local variable in the method body of an anonymous method, it does the following things:

1. Create a new private class as an internal class of classes defined by anonymous methods.

2. Create a public data member in the new class (i.e. inner Class) using the same type and name as the local variable used in the anonymous method body.

3. Create a public instance method in a new class that wraps an anonymous method.

4. Replace the declaration of the local variable with the declaration in the new class. Creates an instance of the new class instead of a local variable's declaration.

5. Replace the local variables used in the body and external of the anonymous method with the data members of the new class instance.

6. Replaces the definition of an anonymous method with the address of an instance method defined in a new class.

So at compile time, the code above will be translated by the C # compiler to the following code:

public class Program
{
Private Class Innerclass
{
private void Instancemethod ()
{
Console.WriteLine (ITEMP);
}
public int itemp;
}
public delegate void MyDelegate ();
public static void Main (string[] args)
{
Innerclass localobject = new Innerclass ();
localobject.itemp = 100;
MyDelegate dlg = new MyDelegate (Localobject.instancemethod);
Dlg ();
}
}
As the pseudo code above shows, the C # compiler generates a private inner class for the ' program ' class. Local variables used in anonymous methods are captured as an instance data member of a new internal class that has been created. And the anonymous method itself is wrapped in an instance method of the inner class. Finally, the instance method is used as a delegate processor in the main method. This way, when a delegate is invoked, there will be a correct value for the local variable that is encapsulated in the anonymous method. The selected section of the following illustration shows a new private inner class that was silently added to the ' program ' class by the C # compiler.


Local variables that are used in anonymous methods have a lifecycle that exceeds the external normal method used for them. This technique, in other languages, is the closures that everyone knows. By removing the simple syntax provided by anonymous methods, closures is a powerful technology that anonymous methods provide to developers. This technique allows the delegate processor code (anonymous method) to access local variables that are defined within the normal method. This allows Out-of-band data, in addition to the delegate parameters, that data is passed to the delegate for use when its methods are executed. Without this technique, each delegate and its corresponding processor method would have to declare parameters that represent local context data, which, over time, would be difficult to manage by constantly declaring parameters that represent local context data. Scope and local variable usage of anonymous methods

We discussed the implementation of anonymous methods in the main scope of the method (the main scope). When an anonymous method is defined in a nested scope, and the anonymous method uses a local variable of the independent scope level, C # creates a private inner class for each scope. For example, suppose Scope 1 has a local variable itemp, and scope 2 is a nested scope of scope 1, with a local variable jtemp. Let's define an anonymous method in scope 2, which uses ITEMP and jtemp from the scope 1 and scope 2 local variables. The following code shows the example described above:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
MyDelegate dlg = null;
int itemp = 100;
if (Itemp > 50)
{
int jtemp = 200;
Dlg = Delegate
{
Console.WriteLine ("Itemp: {0}, Jtemp: {1}", itemp,jtemp);
};
}
Dlg ();
}
}
When the above code is compiled, the C # compiler creates two internal classes in the ' Program ' class. An inner class wraps a local variable itemp as a public data member. The second inner class wraps a local variable in a nested scope, jtemp, as a public data member, while wrapping an anonymous method as a public instance method in the same nested scope. The C # compiler generates the following pseudo code for the above code:

public class Program
{
Wrapping a class of local variable ' itemp ' from an external scope
Private Class InnerClassScope1
{
public int itemp;
}
A class that wraps local variables from both an internal scope and an anonymous method
Private Class InnerClassScope2
{
public void Instancemethod ()
{
Console.WriteLine ("Itemp: {0}, Jtemp: {1}", Localobjectscope1.itemp, jtemp);
}
Public InnerClassScope1 LocalObjectScope1;
public int jtemp;
}
public delegate void MyDelegate ();
public static void Main (string[] args)
{
MyDelegate dlg = null;
InnerClassScope1 LocalObject1 = new InnerClassScope1 ();
localobject1.itemp = 100;
if (Localobject1.itemp > 50)
{
InnerClassScope2 localObject2 = new InnerClassScope2 ();
Localobject2.localobjectscope1 = LocalObject1;
Localobject2.jtemp = 200;
Dlg = new MyDelegate (Localobject2.instancemethod);
}
Dlg ();
}
}
As the preceding code shows, the inner class that wraps an anonymous method will have all objects representing external scope locals, which are used in anonymous methods, like public data members. The following illustration shows the ILDASM view of internal classes created by C # silently:

   use of local variables using anonymous methods within a loop control structure

When dealing with a loop control structure, encapsulating local variables into the data members of the class has the interesting but dangerous side, let's look at the following code:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
MyDelegate d = null;
for (int i = 1; I <= 5; i++)
{
MyDelegate tempd = Delegate
{
Console.WriteLine (i);
};
D + + tempd;
}
D ();
}
}
What output will there be when the above code is run? Our intention is to capture the loop count variable ' i ' in our anonymous method and show it. The output we expect should be as follows:

1
2
3
4
5

But if you run the above code, the output will be as follows:
 
6
6
6
6
6

If we carefully recall our knowledge of the internal working mechanism of anonymous methods, I mention that any local variables captured in the anonymous method will be replaced by a new instance data member of the scope's created inner class. For a loop control variable, the scope is the scope that contains the for loop, which is the main method body as shown in the simple code above. So when the code compiles, the C # compiler generates code that creates an instance of the inner class, wrapping the anonymous method and the loop count variable outside the for loop. And the data member of the instance of the inner class, which represents the loop count variable, will be used instead of the original loop count variable used in the For loop and also in the anonymous method. Therefore, data members from the same instance of the inner class are used for the For loop and are also used in an instance method that wraps an anonymous method. As a result of the loop completion, the instance data member is incremented six times. Here's an important point to note: Although the loop ended after five iterations, the loop count variable was incremented six times as it jumped out of the loop control structure. Since the loop control variable is an instance data member, the sixth increase triggers the loop end condition that has been provided by the loop count variable. Since a method of the same instance is used as a delegate processor for an anonymous method and is invoked at the end of the delegate, all instances of the delegate are pointed to the same instance, and the same value is displayed for the data member, which is 6. This is the dangerous side that I have mentioned in the beginning of this section.

To overcome this problem and get the expected results, the anonymous method should capture a local variable in the scope of the For loop, and it will have the same value as the loop count variable. This can be obtained by modifying the sample code as follows:

public class Program
{
public delegate void MyDelegate ();
public static void Main (string[] args)
{
MyDelegate d = null;
for (int i = 1; I <= 5; i++)
{
int k = i;
MyDelegate tempd = Delegate
{
Console.WriteLine (k);
};
D + + tempd;
}
D ();
}
}
When you run the above code example, you will get the expected output, which is:

1
2
3
4
5

The reason is that the C # compiler will wrap the inner class of the local variable ' k ' to create an instance for each iteration of the For loop. This method of wrapping an anonymous method on an instance of each loop iteration is used as a delegate processor.

   Summary

Anonymous methods are a very useful and powerful feature of the c#2.0 language. In addition to some of the syntax improvements that are introduced to delegate declarations and usages, Microsoft has made great strides in making anonymous method code natural to the included method body, including accessing local variables in the scope of the method definition that contains (anonymous methods). Finally, I want this article to provide the necessary knowledge for C # developers to use anonymous methods correctly and intelligently.



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.