3

C# Lambdas Part 2, a Few More Complicated Examples

 1 year ago
source link: https://nodogmablog.bryanhogan.net/2022/05/c-lambdas-part-2-a-few-more-complicated-examples/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C# Lambdas Part 2, a Few More Complicated Examples

Download full source code.

This post is a continuation of the previous post on C# lambdas. It is not a good as I would like it to be, but as good as I have time to make it. If you have suggestions, please let me know in the comments.

In this, there are a few more complicated examples, maybe even excessively so. But when I hit code like this in a library I was using it took me a while to understand, so I thought I’d share it here.

The rest of this post is sample code, with detailed comments explaining what each line does.

I strongly encourage you to step through the code line by line to see what is being executed, what parameters are being passed, and what is being returned.

A .NET Fiddle of the code is available here.

I know the comments are a little difficult to read in this blog post, but please download the attached zip file or open the .NET Fiddle.

using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Polly; 

public class Program
{
    public static async Task Main()
    {
        // *** Create cancellationToken and httpClient for examples 1 and 2 *** //
        var cts = new CancellationTokenSource(3000);
        var cancellationToken = cts.Token;
        
        HttpClient httpClient = new HttpClient()
        {
            BaseAddress = new System.Uri("https://example.com")
        };


        // *** Example 1 *** //
        var policy = Policy.HandleResult<HttpResponseMessage>( // HandleResult takes a Func that takes a HttpResponseMessage and returns a bool
            r => // Passing the HttpResponseMessage
                !r.IsSuccessStatusCode // Expression lambda returns a bool
            )
            .RetryAsync(3, // RetryAsync takes an int for the retryCount
                onRetry: (response, retryCount) => // and a Action that takes a DelegateResult<HttpResponseMessage> and an int 
                    Console.WriteLine($"Got: {response.Result}. Retrying: {retryCount}") // expression lambda prints to the console. Remember this is an Action, nothing is returned
                 );


        // *** Example 2 *** //
        var response = await policy.ExecuteAsync( // ExecuteAsync takes a Func that takes a CancellationToken returns a Task<HttpResponseMessage>
            (ct) => // CancellationToken
                httpClient.GetAsync("/", ct), // Expression lambda returns a Task<HttpResponseMessage>, the actual CancellationToken is passed to the Func when the Func is executed by Polly
                    cancellationToken); // The CancellationToken created above, this will be passed to the GetAsync method by Polly
        
        Console.WriteLine($"Got a response of: {response.StatusCode}");

        // *** Example 3 *** //
        string firstName = "Alan";
        string runQuery1 =
            RunQuery( // Call to RunQuery. First parameter to RunQuery is a Func that takes a string parameter and returns a string.
                (fieldToSearch) => // Start of expression lambda, it takes a string parameter.
                    BuildQuery(fieldToSearch, firstName), // This is the body of the expression lambda. It calls BuildQuery (which returns a string)...
                                                                   // The value of fieldToSearch has not been set yet.
                     "FirstName"); // this corresponds to fieldToSearch in RunQuery, it will be passed to the lambda.

        Console.WriteLine(runQuery1);


        // *** Example 4 *** //
        string lastName = "Adams";
        string runQuery2 =
            RunQuery(
                (fieldToSearch) =>
                    $"SEARCH {fieldToSearch}:{lastName}", // This is the body of the expression lambda. It returns a string.
                     "LastName"); // This corresponds to fieldToSearch in the lambda on the line above.

        Console.WriteLine(runQuery2);


        #region Local methods
        string RunQuery(Func<string, string> func, string fieldToSearch) // fieldToSearch is "FirstName" in Example 3, and "LastName" in Example 4
        {
            return $"Running a query - {func(fieldToSearch)}";
        }

        string BuildQuery(string fieldToSearch, string valueToSearchFor)
        {
            return $"SEARCH {fieldToSearch}:{valueToSearchFor}";
        }
        #endregion


        // *** Example 5 *** //
        BuildPerson buildPerson = new BuildPerson();
        var resultFromBuildPersonSimple = buildPerson.BuildPersonSimple( // BuildPersonSimple method takes a Func that takes two string parameters and returns a string.
            (firstName, lastName) => // The lambda takes two string parameters.
                $"The person is {firstName} {lastName}", // Expression lambda body takes the two strings and returns a string.
                "Alan", "Adams" // Two strings are passed to the BuildPersonSimple method
            );
        Console.WriteLine(resultFromBuildPersonSimple);


        // *** Example 6 *** //
        var resultFromBuildPersonAdvanced = buildPerson.BuildPersonAdvanced( // BuildPersonSimple method takes a Func that takes two string parameters and an int, and returns a string.
            (firstName, lastName, age) => // The lambda takes two strings and an int as parameters.
                $"The person is {firstName} {lastName}, aged {age} years", // Expression lambda body takes the parameters and returns a string.
                "Betty", "Burns", 30 // Two strings and an int are passed to the BuildPersonAdvanced method
            );
        Console.WriteLine(resultFromBuildPersonAdvanced);



        // *** Example 7 *** //
        OtherMethods otherMethods = new OtherMethods();
        var resultFromOtherMethods = otherMethods.Top( //Top takes a Func that takes two int parameters and returns a string.
            (a, b) =>  // The lambda takes two int parameters.
                $"Example 6. Result of a + b ({a} + {b}) is {a + b}", // Expression lambda body performs a simple calculation, and returns a string.
                5 // Passed to the Top method as num1 
            );

        Console.WriteLine(resultFromOtherMethods);
    }
}

public class OtherMethods
{
    public string Top(Func<int, int, string> func, int num1)
     => Bottom((x, y) => func(x, y), num1); // Top method does nothing except call Bottom, passing the func and num1(5).

    public string Bottom(Func<int, int, string> func, int num1)
    {
        int localNumber = 10; 
        return func(num1, localNumber); // num1 and localNumber are passed to the lambda.
    }
}
public class BuildPerson
{
    public string BuildPersonSimple(Func<string, string, string> buildPersonSimpleFunc, string firstName, string lastName)
    => BuildPersonAdvanced( // Call to BuildPersonAdvanced method, BuildPersonAdvanced takes a Func that takes a two strings an an int as parameters and returns a string.
        (firstName, lastName, _) => // Because the Func parameter to BuildPersonAdvanced takes two strings and an int, I have to pass in three parameters, but I discarded the int because I don't have an age to pass.
            buildPersonSimpleFunc(firstName, lastName), // The Func in BuildPersonAdvanced must return a string, buildPersonSimpleFunc returns a string, so it can be used here.
          firstName, lastName, default(int)); // Pass on the two strings. But not passing anything for age, so using default(int).


    public string BuildPersonAdvanced(Func<string, string, int, string> buildPersonAdvancedFunc, string firstName, string lastName, int age)
    {
        // This is where things get more complicated.
        // Look at buildPersonAdvancedFunc it takes two strings, and an int, and returns a string. 
        // But you can see from the BuildPersonSimple Method, that the buildPersonSimpleFunc that was passed to BuildPersonAdvanced as buildPersonAdvancedFunc, but buildPersonSimpleFunc only takes two strings, and returns a string. It doesn't take an int.
        // Now to invoke buildPersonAdvancedFunc, you must pass in two strings, and an int. 
        // For example 5, the age will not be used, but for example 6 it will be. 
        
        return $"{buildPersonAdvancedFunc(firstName, lastName, age)}";
    }
}

Download full source code.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK