Anonymous Methods


An anonymous method is a nameless method. Sometimes a function is intended exclusively for a delegate. Without an anonymous method, you would have to define a separate function as part of a class. The function can then be assigned to the delegate. Assigning an anonymous method prevents creating a separate method. This is cleaner and more convenient than a named method. Anonymous methods can substitute for delegates as parameters, return values, and in other situations.

Define an anonymous method with the delegate keyword. This code assigns an anonymous method to a delegate:

 using System; using System.Threading; namespace Donis.CSharpBook{      public delegate void DelegateClass();      public class Starter{          public static void Main(){              DelegateClass del= delegate {                  Console.WriteLine("Running anonymous method");              };              del();          }      } } 

In the preceding example, the anonymous method does not have a signature. The signature of the anonymous method is inferred from the delegate signature, which is another example of delegate inference. Despite not having a signature, the return of the anonymous method must match the delegate return. The advantage of an anonymous method without a signature is its compliance with almost any delegate. The disadvantage is that anonymous methods defined without a signature cannot access the parameters of the delegates. This means that the anonymous method cannot utilize the parameters. For this reason, anonymous methods without a signature cannot be employed where delegates have out parameters. Out parameters must be initialized in the called method, which is impossible in an anonymous method. When an anonymous method is called through the delegates, the parameters must still be provided, even if ignored inside the method. Of course, if the delegate has no parameters, none should be provided.

This is the syntax of an anonymous method:

  • delegate optional_signature {anonymous method expression}

The C# compiler performs several tasks to assign an anonymous method without a signature to a delegate:

  1. Validates the signature of the delegate—no out parameters

  2. Infers the signature of the anonymous method from the delegate

  3. Confirms that the return type of the delegate is compatible with the anonymous method

  4. Creates a new delegate that is initialized with a function pointer to the anonymous method

Anonymous methods can be assigned a signature, which is appended to the delegate keyword. This restricts the anonymous method to a delegate with a matching signature and return type. Like conventional methods, the parameters are initialized with the parameters from the delegate call. This is an example of an anonymous method with a signature:

 using System; using System.Threading; namespace Donis.CSharpBook{      public delegate int DelegateClass(out int param);      public class Starter{          public static void Main(){              int var;              DelegateClass del= delegate(out int inner) {                  inner=12;                  Console.WriteLine("Running anonymous method");                  return inner;              };              del(out var);              Console.WriteLine("Var is {0}", var);          }      } } 

As demonstrated in the preceding code, anonymous methods can be used for delegates. The exception is the -= assignment operator. Because the anonymous method is unnamed, it cannot be used to remove a named method from a multicast delegate. This is the exception to freely substituting delegates with anonymous methods.

Actually, anonymous methods are not nameless. The C# compiler implements the anonymous method as the named method in the containing class. The generated method is both static and private. The wrapper delegate is initialized with this method. The following format is used to name anonymous methods:

  • <functionname>uniqueid

The function name is the function in which the anonymous method is implemented. The unique identifier is a combination of a letter and number. The method has the same signature as the target delegate.

The wrapper delegate initialized with the anonymous method is also added to the class as a static and private field. This is the format of the wrapper delegate. The identifier is a compiler-generated number, whereas # is a character added to the name of the wrapper delegate.

<>id__CachedAnonymousMethodDelegate#

The following code offers two delegates and anonymous methods:

 using System; namespace Donis.CSharpBook{      public delegate void ADelegate(int param);      public delegate int BDelegate(int param1, int param2);      public class Starter{          public static void Main(){              ADelegate del= delegate(int param) {                  param=5;              };          }          public int MethodA() {              BDelegate del= delegate(int param1, int param2) {                  return 0;              };              return 0;          }      } } 

Figure 8-3 is a disassembly of this application program. It shows the wrapper delegates and anonymous methods.

image from book
Figure 8-3: Disassembly showing wrapper delegates and anonymous methods

Outer Variables

Anonymous methods can refer to local variables of the containing function and class members within the scope of the method definition. Local variables used in an anonymous method are called outer variables.

The scope of a local variable is closely linked to the method in which the local is declared. When the method ends, local variables are removed from memory. Local variables used in an anonymous method are captured, which extends the lifetime of the variable. The lifetime of a captured or outer variable is of the same as that of the delegate. The outer variable is removed when the delegate is garbage-collected. In the following code, the local variable of MethodA is captured in the anonymous method. The lifetime of the local variable would usually end when MethodA is exited. However, the delegate is garbage-collected until the end of the program, which extends the lifetime of the local variable for the entire program.

 using System; namespace Donis.CSharpBook{      public delegate void DelegateClass(out int arg);      public class Starter{          public static void Main(){              DelegateClass del=MethodA();              int var;              del(out var);              Console.WriteLine(var);          }          public static DelegateClass MethodA() {              int local=0;              return delegate(out int arg) {                  arg=++local;              };          }      } } 

Because the lifetime of outer variables is aligned with the delegate, it remains persistent across invocations of the anonymous method. In the following code, the anonymous method is invoked thrice through the delegate. As a local variable, local would be initialized on each call to the method. However, as an outer variable, it is initialized once in MethodA and maintains its value across multiple calls to the anonymous method. Therefore, the value displayed is 3.

 using System; namespace Donis.CSharpBook{      public delegate void DelegateClass(out int var);      public class Starter{          public static void Main(){              DelegateClass del=MethodA();              int var;              del(out var);              del(out var);              del(out var);              Console.WriteLine(var);          }          public static DelegateClass MethodA() {              int increment=0;              return delegate(out int var) {                  var=++increment;              };          }      } } 

The C# compiler creates a private nested class for anonymous methods that capture local variables, whereas anonymous methods that contain no outer variables are implemented as private static methods. The nested class has a public field for each outer variable used in the anonymous method. The local variable is persisted to this public field. It also contains a named method for the anonymous method. The named method has the same signature as the related delegate. This is the method used to initialize the wrapper delegate. Figure 8-4 illustrates the nested class created for an anonymous method.

image from book
Figure 8-4: Disassembly of nested class for an anonymous method that uses outer variables

Locals are fixed variables and are not normally available to garbage collection. Local variables are removed from memory when the applicable method is exited. When a local variable is captured, it becomes a movable variable. Movable variables are placed on the managed heap. As such, outer variables then become available for garbage collection. For this reason, captured variables must be pinned or otherwise fixed before being used with unsafe code.

Generic Anonymous Methods

Anonymous methods can use generic parameters of the class or delegate. However, anonymous methods cannot define new generic parameters and constraints. Here are two examples of anonymous methods using generic parameters:

 public delegate void ADelegate<T>(T tvalue); public class ZClass{     public void MethodA() {         ADelegate<int> del=delegate(int var) {         };     } } public class YClass<T>{     public delegate void BDelegate(T tValue);     public void MethodA() {         BDelegate del=delegate(T tValue) {         };     } } 

Limitations of Anonymous Methods

Although anonymous methods are similar to other methods, they also have some limitations (some have already been mentioned):

  • Do not attempt to jump out of an anonymous method.

  • Do not use a ref or out outer variable in an anonymous method.

  • Do not define new generic parameters or constraints.

  • Do not apply attributes to anonymous methods.

  • Do not use anonymous method with -= assignment operator.

  • Cannot be a member method.

  • Cannot be an unsafe method.




Programming Microsoft Visual C# 2005(c) The Language
Microsoft Visual Basic 2005 BASICS
ISBN: 0619267208
EAN: 2147483647
Year: 2007
Pages: 161

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net