Home > Articles > Programming > C#

This chapter is from the book

7.14 Anonymous Function Expressions

An anonymous function is an expression that represents an “in-line” method definition. An anonymous function does not have a value in and of itself, but rather is convertible to a compatible delegate or expression tree type. The evaluation of an anonymous function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method that the anonymous function defines. If it is an expression tree type, the conversion evaluates to an expression tree that represents the structure of the method as an object structure.

For historical reasons, two syntactic flavors of anonymous functions exist—namely, lambda-expressions and anonymous-method-expressions. For almost all purposes, lambda-expressions are more concise and expressive than anonymous-method-expressions, which remain in the language for backward compatibility.

lambda-expression:
   anonymous-function-signature => anonymous-function-body
anonymous-method-expression:
    delegate explicit-anonymous-function-signatureopt block
anonymous-function-signature:
    explicit-anonymous-function-signature
    implicit-anonymous-function-signature
explicit-anonymous-function-signature:
     ( explicit-anonymous-function-parameter-listopt )
explicit-anonymous-function-parameter-list
     explicit-anonymous-function-parameter
     explicit-anonymous-function-parameter-list , explicit-anonymous-function-parameter
explicit-anonymous-function-parameter:
     anonymous-function-parameter-modifieropt type identifier
anonymous-function-parameter-modifier:
    ref
    out
implicit-anonymous-function-signature:
     ( implicit-anonymous-function-parameter-listopt )
     implicit-anonymous-function-parameter
implicit-anonymous-function-parameter-list
    implicit-anonymous-function-parameter
    implicit-anonymous-function-parameter-list , implicit-anonymous-function-parameter
implicit-anonymous-function-parameter:
    identifier
anonymous-function-body:
    expression
    block

The => operator has the same precedence as assignment (=) and is right-associative.

The parameters of an anonymous function in the form of a lambda-expression can be explicitly or implicitly typed. In an explicitly typed parameter list, the type of each parameter is explicitly stated. In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the anonymous function occurs—specifically, when the anonymous function is converted to a compatible delegate type or expression tree type, that type provides the parameter types (§6.5).

In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, an anonymous function of the form

    ( param ) => expr

can be abbreviated to

    
   param => expr

The parameter list of an anonymous function in the form of an anonymous-method-expression is optional. If given, the parameters must be explicitly typed. If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Some examples of anonymous functions follow:

x => x + 1

// Implicitly typed, expression body

x => { return x + 1; }

// Implicitly typed, statement body

(int x) => x + 1

// Explicitly typed, expression body

(int x) => { return x + 1; }

// Explicitly typed, statement body

(x, y) => x * y

// Multiple parameters

() => Console.WriteLine()

// No parameters

delegate (int x) { return x + 1; }

// Anonymous method expression

delegate { return 1 + 1; }

// Parameter list omitted

The behavior of lambda-expressions and anonymous-method-expressions is the same except for the following points:

  • anonymous-method-expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • lambda-expressions permit parameter types to be omitted and inferred, whereas anonymous-method-expressions require parameter types to be explicitly stated.
  • The body of a lambda-expression can be an expression or a statement block, whereas the body of an anonymous-method-expression must be a statement block.
  • Because only lambda-expressions can have expression bodies, no anonymous-method-expression can be successfully converted to an expression tree type (§4.6).

7.14.1 Anonymous Function Signatures

The optional anonymous-function-signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. The scope of the parameters of the anonymous function is the anonymous-function-body (§3.7). Together with the parameter list (if given), the anonymous-method-body constitutes a declaration space (§3.3). For this reason, it is a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant, or parameter whose scope includes the anonymous-method-expression or lambda-expression.

If an anonymous function has an explicit-anonymous-function-signature, then the set of compatible delegate types and expression tree types is restricted to those that have the same parameter types and modifiers in the same order. In contrast to method group conversions (§6.6), contravariance of anonymous function parameter types is not supported. If an anonymous function does not have an anonymous-function-signature, then the set of compatible delegate types and expression tree types is restricted to those that have no out parameters.

An anonymous-function-signature cannot include attributes or a parameter array. Nevertheless, an anonymous-function-signature may be compatible with a delegate type whose parameter list contains a parameter array.

Note that conversion to an expression tree type, even if compatible, may still fail at compile time (§4.6).

7.14.2 Anonymous Function Bodies

The body (expression or block) of an anonymous function is subject to the following rules:

  • If the anonymous function includes a signature, the parameters specified in the signature are available in the body. If the anonymous function has no signature, it can be converted to a delegate type or expression type having parameters (§6.5), but the parameters cannot be accessed in the body.
  • Except for ref or out parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access a ref or out parameter.
  • When the type of this is a struct type, it is a compile-time error for the body to access this. This is true whether the access is explicit (as in this.x) or implicit (as in x where x is an instance member of the struct). This rule simply prohibits such access and does not affect whether member lookup returns a member of the struct.
  • The body has access to the outer variables (§7.14.4) of the anonymous function. Access of an outer variable will reference the instance of the variable that is active at the time the lambda-expression or anonymous-method-expression is evaluated (§7.14.5).
  • It is a compile-time error for the body to contain a goto statement, break statement, or continue statement whose target is outside the body or within the body of a contained anonymous function.
  • A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. An expression specified in a return statement must be compatible with the delegate type or expression tree type to which the nearest enclosing lambda-expression or anonymous-method-expression is converted (§6.5).

It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda-expression or anonymous-method-expression. In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. The names of any such synthesized elements must be of a form reserved for compiler use.

7.14.3 Overload Resolution

Anonymous functions in an argument list participate in type inference and overload resolution. Refer to §7.4.2.3 for the exact rules governing their behavior.

The following example illustrates the effect of anonymous functions on overload resolution.

  class ItemList<T>: List<T>
  {
      public int Sum(Func<T,int> selector) {
          int sum = 0;
          foreach (T item in this) sum += selector(item);
          return sum;
      }

      public double Sum(Func<T,double> selector) {
          double sum = 0;
          foreach (T item in this) sum += selector(item);
          return sum;
      }
  }

The ItemList<T> class has two Sum methods. Each takes a selector argument, which extracts the value to sum over from a list item. The extracted value can be either an int or a double, and the resulting sum is likewise either an int or a double.

The Sum methods could, for example, be used to compute sums from a list of detail lines in some order.

  class Detail
  {
      public int UnitCount;
      public double UnitPrice;
      ...
  }
  void ComputeSums() {
      ItemList<Detail> orderDetails = GetOrderDetails(...);
      int totalUnits = orderDetails.Sum(d => d.UnitCount);
      double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
      ...
  }

In the first invocation of orderDetails.Sum, both Sum methods are applicable because the anonymous function d => d.UnitCount is compatible with both Func<Detail,int> and Func<Detail,double>. However, overload resolution picks the first Sum method because the conversion to Func<Detail,int> is better than the conversion to Func<Detail,double>.

In the second invocation of orderDetails.Sum, only the second Sum method is applicable because the anonymous function d => d.UnitPrice * d.UnitCount produces a value of type double. Thus overload resolution picks the second Sum method for that invocation.

7.14.4 Outer Variables

Any local variable, value parameter, or parameter array whose scope includes the lambda-expression or anonymous-method-expression is called an outer variable of the anonymous function. In an instance function member of a class, the this value is considered a value parameter and is an outer variable of any anonymous function contained within the function member.

7.14.4.1 Captured Outer Variables

When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (§5.1.7). However, the lifetime of a captured outer variable is extended at least until the delegate or expression tree created from the anonymous function becomes eligible for garbage collection.

In the example

  using System;

  delegate int D();

  class Test
  {

      static D F() {
          int x = 0;
          D result = () => ++x;
          return result;
      }

      static void Main() {
          D d = F();
          Console.WriteLine(d());
          Console.WriteLine(d());
          Console.WriteLine(d());
      }
  }

the local variable x is captured by the anonymous function, and the lifetime of x is extended at least until the delegate returned from F becomes eligible for garbage collection (which doesn’t happen until the very end of the program). Because each invocation of the anonymous function operates on the same instance of x, the example produces the following output:

  1
  2
  3

When a local variable or a value parameter is captured by an anonymous function, the local variable or parameter is no longer considered to be a fixed variable (§18.3), but is instead considered to be a moveable variable. Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

7.14.4.2 Instantiation of Local Variables

A local variable is considered to be instantiated when execution enters the scope of the variable. For example, when the following method is invoked, the local variable x is instantiated and initialized three times—once for each iteration of the loop.

  static void F() {
      for (int i = 0; i < 3; i++) {
          int x = i * 2 + 1;
          ...
      }
  }

By comparison, moving the declaration of x outside the loop results in a single instantiation of x:

  static void F() {
      int x;
      for (int i = 0; i < 3; i++) {
          x = i * 2 + 1;
          ...
      }
  }

When not captured, there is no way to observe exactly how often a local variable is instantiated—because the lifetimes of the instantiations are disjoint, it is possible for each instantiation to simply use the same storage location. However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

The example

  using System;

  delegate void D();

  class Test
  {
      static D[] F() {
          D[] result = new D[3];
          for (int i = 0; i < 3; i++) {
              int x = i * 2 + 1;
              result[i] = () => { Console.WriteLine(x); };

          }
          return result;

      }

      static void Main() {
          foreach (D d in F()) d();
      }
  }

produces the following output:

  1
  3
  5

When the declaration of x is moved outside the loop,

  static D[] F() {
      D[] result = new D[3];
      int x;
      for (int i = 0; i < 3; i++) {
          x = i * 2 + 1;
          result[i] = () => { Console.WriteLine(x); };
      }
      return result;
  }

the output changes as follows:

  5
  5
  5

If a for-statement declares an iteration variable, that variable itself is considered to be declared outside of the loop. Thus, if the example is changed to capture the iteration variable itself,

  static D[] F() {
      D[] result = new D[3];
      for (int i = 0; i < 3; i++) {
          result[i] = () => { Console.WriteLine(i); };
      }
      return result;
  }

only one instance of the iteration variable is captured, which produces the following output:

  3
  3
  3

It is possible for anonymous function delegates to share some captured variables, yet have separate instances of others. For example, if F is changed to

  static D[] F() {
      D[] result = new D[3];
      int x = 0;
      for (int i = 0; i < 3; i++) {
          int y = 0;
          result[i] = () => { Console.WriteLine("{0} {1}", ++x, ++y); };
      }
      return result;
  }

the three delegates capture the same instance of x but separate instances of y, and the output is as follows:

  1 1
  2 1
  3 1

Separate anonymous functions can capture the same instance of an outer variable. In the example

  using System;

  delegate void Setter(int value);

  delegate int Getter();

  class Test
  {

      static void Main() {
          int x = 0;
          Setter s = (int value) => { x = value; };
          Getter g = () => { return x; };
          s(5);
          Console.WriteLine(g());
          s(10);
          Console.WriteLine(g());
      }
  }

the two anonymous functions capture the same instance of the local variable x, and they can “communicate” through that variable. This example results in the following output:

  5
  10

7.14.5 Evaluation of Anonymous Function Expressions

An anonymous function F must always be converted to a delegate type D or an expression tree type E, either directly or through the execution of a delegate creation expression new D(F). This conversion determines the result of the anonymous function, as described in §6.5.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020