C × lambda expression learning notes

This note is excerpted from: https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html Record the learning process for future reference.

I. significance of Lambda

Before Framework 2.0, the only way to declare delegates was through method naming. Since Framework 2.0, anonymous methods have been supported. Through anonymous method, you can directly bind a piece of code

Give events, thus reducing the coding overhead required to instantiate delegates. At the beginning of Framework 3.0, Lambda expressions gradually replaced anonymous methods as the preferred way to write inline code.

In general, the purpose of Lambda expression is to write anonymous methods in a simpler way, and to completely simplify the use of delegates.

2. Review the use of anonymous methods

The use of anonymous methods in C. delegation and event learning notes There is a brief introduction in. Let's review:

        static void Main(string[] args)
        {
            #region Event usage and method binding
            PersonManager personManager = new PersonManager();
            //Binding event handling method 1
            personManager.MyEvent += new MyDelegate(GetName);
            //Binding event handling method 2
            personManager.MyEvent += GetName;
            //Binding event handling method 3(Anonymous Methods )
            personManager.MyEvent += delegate (string name) { Console.WriteLine("My name is " + name); };
            personManager.Execute("Atomy");
            Console.Read();
            #endregion
        }

It's depressing to always use delegate () {...} to create anonymous methods. From Framework 3.0 onwards, Lambda expressions begin to appear.

3. A brief introduction to generic delegation

Before I introduce Lambda expressions, I'll introduce some common generic delegates.

3.1 generic delegate predicate < T >

As early as Framework 2.0, Microsoft added Find, FindAll, ForEach and other methods to the list < T > class for data search.

    public T Find ( Predicate<T> match)

    public List<T> FindAll(Predicate<T>  match)

In these methods, there is a predicate < T > expression, which is a generic delegate that returns bool and can accept an object of any type as a parameter.

    public delegate bool Predicate<T>(T obj)

In the following example, the Predicate delegate binds the method Match with the parameter of Person class as the query criteria, and then uses the FindAll method to find the list < Person > collection with the appropriate criteria.

    class Program
    {
        #region generic delegate  Predicate<T>
        /// <summary>
        /// Person class
        /// </summary>
        class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }

            public Person(int id, string name, int age)
            {
                Id = id;
                Name = name;
                Age = age;
            }
        }

        /// <summary>
        /// data source
        /// </summary>
        /// <returns></returns>
        static List<Person> GetList()
        {
            var personList = new List<Person>();
            var person = new Person(1, "Hello", 29);
            personList.Add(person);
            person = new Person(1, "World", 31);
            personList.Add(person);
            return personList;
        }

        /// <summary>
        /// query criteria
        /// </summary>
        /// <param name="person"></param>
        /// <returns></returns>
        static bool Match(Person person)
        {
            return person.Age <= 30;
        }
        #endregion

        static void Main(string[] args)
        {
            #region generic delegate  Predicate<T>
            List<Person> list = GetList();
            //Bind query criteria
            Predicate<Person> predicate = new Predicate<Person>(Match);
            List<Person> result = list.FindAll(predicate);
            Console.WriteLine($"Person count is : {result.Count}");
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

3.2 generic delegate Action

The usage of action < T > is similar to that of predicate < T > except that the return value of predicate < T > is bool and the return value of action < T > is void.

Action supports 0-16 parameters and can be used as required.

    public delegate void Action()

    public delegate void Action<T1> (T1 obj1)

    public delegate void Action<T1,T2> (T1 obj1, T2 obj2)

    public delegate void Action<T1,T2,T3> (T1 obj1, T2 obj2,T3 obj3)

    ............

    public delegate void Action<T1,T2,T3,......,T16> (T1 obj1, T2 obj2,T3 obj3,......,T16 obj16)

The following code demonstrates the generic delegate Action:

    class Program
    {
        #region generic delegate  Action
        static void ShowMessage(string message)
        {
            Console.WriteLine(message);
        }
        #endregion

        static void Main(string[] args)
        {
            #region generic delegate  Action
            Action<string> action = ShowMessage;
            action("Hello World");
            Console.ReadKey();
            #endregion
        }
    }

The operation results are as follows:

3.3 generic delegate Func

Delegate Func is similar to Action, and also supports 0-16 parameters. The difference is that Func must have a return value.

    public delegate TResult Func<TResult>()

    public delegate TResult Func<T1,TResult>(T1 obj1)

    public delegate TResult Func<T1,T2,TResult>(T1 obj1,T2 obj2)

    public delegate TResult Func<T1,T2,T3,TResult>(T1 obj1,T2 obj2,T3 obj3)

    ............

    public delegate TResult Func<T1,T2,T3,......,T16,TResult>(T1 obj1,T2 obj2,T3 obj3,......,T16 obj16)

The following code demonstrates the generic delegate Func:

    class Program
    {
        #region generic delegate  Func
        static double Account(double a, bool condition)
        {
            if (condition)
                return a * 1.5;
            else
                return a * 2;
        }
        #endregion

        static void Main(string[] args)
        {
            #region generic delegate  Func
            Func<double, bool, double> func = Account;
            double result = func(1000, true);
            Console.WriteLine($"Result is : {result}");
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

IV. unveiling the mystery of Lambda

Lambda's expression is written in the following format: x = > x * 1.5

In which "= > is the operator of Lambda expression. It is used to define a parameter list on the left and operate these parameters on the right.

Example 1: first, set int x to 1000, define the expression as x=x+500 through Action, and finally Invoke the delegate.

    class Program
    {
        static void Main(string[] args)
        {
            #region Lambda Example 1
            int x = 1000;
            Action action = () => x = x + 500;
            action.Invoke();

            Console.WriteLine($"Result is : {x}");
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

Example 2: define the expression x=x+500 through action < int > and input parameter 1000 at last. The result is the same as that of example 1.

Note that the operations defined by Lambda expressions here are enclosed in {} brackets, which can contain a series of operations.

    class Program
    {
        static void Main(string[] args)
        {
            #region Lambda Example 2
            Action<int> action = (x) =>
            {
                x = x + 500;
                Console.WriteLine($"Result is : {x}");
            };
            action.Invoke(1000);
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

Example 3: define a predicate < int > and return true when the input value is about 1000, otherwise return false. Compared with the example in 3.1, the binding of predicate < T > does not need to explicitly establish a method,

It is directly completed in Lambda expression, which is quite simple and convenient.

    class Program
    {
        static void Main(string[] args)
        {
            #region Lambda Example 3
            Predicate<int> predicate = (x) =>
            {
                if (x >= 1000)
                    return true;
                else
                    return false;
            };
            bool result = predicate.Invoke(500);
            Console.WriteLine($"Result={result}");
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

Example 4: when calculating the price of a commodity, if the weight of the commodity exceeds 30kg, 10% discount will be given, and others will be handled according to the original price. At this time, you can use func < double, int, double >, parameter 1 is the original price of the product, and parameter 2 is the product

Weight, and the final return value is double.

    class Program
    {
        static void Main(string[] args)
        {
            #region Lambda Example 4
            Func<double, int, double> func = (price, weight) =>
            {
                if (weight >= 30)
                    return price * 0.9;
                else
                    return price;
            };
            double totalPrice = func(200.0, 40);
            Console.WriteLine($"TotalPrice={totalPrice}");
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

Example 5: using Lambda to define the handling method of Click event for Button is simpler than using anonymous method.

    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }

        private void Main_Load(object sender, EventArgs e)
        {
            #region Lambda Example 5
            btnEvent.Click += (obj,arg)=>
            {
                MessageBox.Show("Hello World");
            };
            #endregion
        }
    }

The operation results are as follows:

Example 6: use the example of 3.1 here, and use the Lambda expression directly in the FindAll method of list < person >. In contrast, with Lambda expressions, you don't need to define a predicate < T > object

There is no need to explicitly set the binding method, which simplifies the non process.

    class Program
    {
        #region generic delegate  Predicate<T>
        /// <summary>
        /// Person class
        /// </summary>
        class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }

            public Person(int id, string name, int age)
            {
                Id = id;
                Name = name;
                Age = age;
            }
        }

        /// <summary>
        /// data source
        /// </summary>
        /// <returns></returns>
        static List<Person> GetList()
        {
            var personList = new List<Person>();
            var person = new Person(1, "Hello", 29);
            personList.Add(person);
            person = new Person(1, "World", 31);
            personList.Add(person);
            return personList;
        }

        /// <summary>
        /// query criteria
        /// </summary>
        /// <param name="person"></param>
        /// <returns></returns>
        static bool Match(Person person)
        {
            return person.Age <= 30;
        }
        #endregion

        static void Main(string[] args)
        {
            #region Lambda Example 6
            List<Person> personList = GetList();
            //Find people under 30 years of age
            List<Person> result = personList.FindAll((person) => person.Age <= 30);
            Console.WriteLine("Person count is : " + result.Count);
            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

When using LINQ technology, Lambda will be everywhere, which can better reflect the advantages of Lambda. But LINQ involves partial classes, partial methods, IEnumerable < T >, iterators, etc

This is beyond the scope of this chapter. Through the introduction of this section, I hope to help you understand the use of Lambda more deeply.

Keywords: C# Lambda

Added by laduch on Mon, 23 Dec 2019 09:47:03 +0200