4 minute read

How to improve code readability?

Lambda Expression Doc

You use a lambda expression to create an anonymous function. Use the lambda declaration operator => to separate the lambda’s parameter list from its body. A lambda expression can be of any of the following two forms:

  • Expression lambda that has an expression as its body:
(input-parameters) => expression
  • Statement lambda that has a statement block as its body:
(input-parameters) => { <sequence-of-statements> }
// Lambda Expression
using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            // Local function
            bool compareMethod(int a, int b)
            {
                return a == b;
            }

            // Expression lambda
            bool compareLambda(int a, int b) => (a == b);
            Console.WriteLine(compareMethod(3, 4));
            // Console.WriteLine(compareLambda(3, 4));

            // Print a Fibonacci sequence
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("The {0} term of the Fibonacci sequence is {1:N0}.",
                  arg0: i + 1,
                  arg1: FibLambda(term: i));
                //   arg1: FibMethod(term: i));
            }
        }

        // Fibonacci sequence
        static int FibMethod(int term)
        {
            switch (term)
            {
                case 0:
                    return 0;
                case 1:
                    return 1;
                default:
                    return FibMethod(term - 1) + FibMethod(term - 2);
            }
        }

        // Fibonacci sequence
        // Statement lambda
        static int FibLambda(int term) => term switch
        {
            0 => 0,
            1 => 1,
            _ => FibLambda(term - 1) + FibLambda(term - 2)
        };
    }
}

Delegates Doc

Basic Delegates

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature (the method name, and the type and order of parameters) and return type. You can invoke (or call) the method through the delegate instance.

using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            GenerateMyNumbers generateRandom = new GenerateMyNumbers(GetRandomNumber);
            GenerateMyNumbers generateOrdered = new GenerateMyNumbers(GetOrderedNumber);

            // int[] numbers = generateRandom(10, 3);
            int[] numbers = generateOrdered(10, 3);

            foreach (int n in numbers)
            {
                Console.Write(n + " ");
            }
            Console.WriteLine();
        }

        // My first delegate
        public delegate int[] GenerateMyNumbers(int x, int y);
        // Create an arry with size amount and assign a random value 0-maxNum in this array
        public static int[] GetRandomNumber(int maxNum, int amount)
        {
            Random random = new Random();
            int[] nums = new int[amount];

            for (int i = 0; i < amount; i++)
            {
                // 0 ~ maxNum-1
                nums[i] = random.Next(0, maxNum);
            }
            return nums;
        }
        // Get an ordered integer sequence from min to max
        public static int[] GetOrderedNumber(int max, int min)
        {
            // Avoid when max is smaller than min
            if (max < min)
            {
                int[] noNum = { 0 };
                return noNum;
            }

            // Create an ordered sequence
            int[] nums = new int[max - min + 1];
            for (int i = 0; i <= max - min; i++)
            {
                nums[i] = min + i;
            }
            return nums;
        }
    }
}
$ 3 4 5 6 7 8 9 10
  • Delegates are used to pass methods as arguments to other methods.
  • Delegates can be used to define callback methods.
  • Delegates can be chained together; for example, multiple methods can be called on a single event.
  • Lambda expressions (in certain contexts) are compiled to delegate types.
using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            // string.Join: method that lets you concatenate each element in an
            // object array without explicitly converting its elements to strings
            Console.WriteLine(string.Join(",", Change1(array)));
            Console.WriteLine(string.Join(",", Change2(array)));
            Console.WriteLine(string.Join(",", Change3(array)));
        }

        // Take out each elemnt in an array and +1
        public static int[] Change1(int[] _array)
        {
            var array = new int[_array.Length];
            for (int i = 0, c = _array.Length; i < c; i++)
            {
                array[i] = _array[i] + 1;
            }
            return array;
        }
        // Take out each elemnt in an array and *2
        public static int[] Change2(int[] _array)
        {
            var array = new int[_array.Length];
            for (int i = 0, c = _array.Length; i < c; i++)
            {
                array[i] = _array[i] * 2;
            }
            return array;
        }
        // Take out each elemnt in an array and square it
        public static int[] Change3(int[] _array)
        {
            var array = new int[_array.Length];
            for (int i = 0, c = _array.Length; i < c; i++)
            {
                array[i] = _array[i] * _array[i];
            }
            return array;
        }
    }
}
$ 2,3,4,5,6,7,8,9,10
$ 2,4,6,8,10,12,14,16,18
$ 1,4,9,16,25,36,49,64,81
using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            // Create three delegate objects that take differentmethods as parameters
            MyDelegate myDelegate1 = new MyDelegate(AddOne);
            MyDelegate myDelegate2 = new MyDelegate(MultipleTwo);
            MyDelegate myDelegate3 = new MyDelegate(Square);
            // Syntactic sugar
            // syntactic sugar is syntax within a programming language that is
            // designed to make things easier to read or to express.
            // The following is also a valid syntax;
            // MyDelegate myDelegate3 = Square;

            // string.Join: method that lets you concatenate each element in an
            // object array without explicitly converting its elements to strings
            Console.WriteLine(string.Join(",", Change(array, myDelegate1)));
            Console.WriteLine(string.Join(",", Change(array, myDelegate2)));
            Console.WriteLine(string.Join(",", Change(array, myDelegate3)));
        }

        // Declaration of the delegete
        public delegate int MyDelegate(int x);

        public static int AddOne(int number)
        {
            return number+1;
        }
        public static int MultipleTwo(int number)
        {
            return number*2;
        }
        public static int Square(int number)
        {
            return number * number;
        }

        // A method Change that takes another method as the input parameters
        // In this case, the method (as a parameter) should be defined as a delegate
        public static int[] Change(int[] _array, MyDelegate myDelegate)
        {
            var array = new int[_array.Length];
            for (int i = 0, c = _array.Length; i < c; i++)
            {
                array[i] = myDelegate(_array[i]);
            }
            return array;
        }
    }
}
$ 2,3,4,5,6,7,8,9,10
$ 2,4,6,8,10,12,14,16,18
$ 1,4,9,16,25,36,49,64,81

Lambda Expression with Delegates

public static int Square(int number) => number * number;

Func, Action and Predicate Delegates

  • Action Delegate: Encapsulates a method that has a single parameter and does not return a value. Doc
using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            Action<int, int> Addition = new Action<int, int>(AddNumbers);
            // Alternative
            // Action<int, int> Addition = AddNumbers;  
            Addition(10, 20);
        }

        // add param1 and param2 and return the sum
        private static void AddNumbers(int param1, int param2)
        {
            int result = param1 + param2;
            Console.WriteLine($"Addition = {result}");
        }
    }
}
$ Addition = 30
  • Func<T,TResult> Delegate: Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter. Doc
using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            // Declare a Func delegate
            Func<int, int, int> Addition = new Func<int, int, int>(AddNumbers);
            // Func<int, int, int> Addition = AddNumbers;
            // Using Lambda Expression
            // Func<int, int, int> Addition = (param1, param2) => param1 + param2;  

            int result = Addition(10, 20);
            Console.WriteLine($"Addition = {result}");
        }

        // add param1 and param2 and return the sum
        private static int AddNumbers(int param1, int param2)
        {
            return param1 + param2;
        }
    }
}
$ Addition = 30
  • Advantages of Action and Func Delegates
    • Easy and quick to define delegates.
    • Makes code short.
    • Compatible type throughout the application.
  • Predicate Delegate: Represents the method that defines a set of criteria and determines whether the specified object meets those criteria. Doc

Syntax difference between predicate & func is that here in predicate, you don’t specify a return type because it is always a bool.

using System;

namespace MyBusiness
{
    class Program
    {
        static void Main(string[] args)
        {
            Predicate<string> CheckIfApple = new Predicate<string>(IsApple);
            // Predicate<string> CheckIfApple = IsApple;
            bool result = IsApple("I Phone X");
            if (result){
                Console.WriteLine("It's an IPhone");
            }
        }

        private static bool IsApple(string modelName)
        {
            // Check if the model name an iPhone
            if (modelName == "I Phone X")
                return true;
            else
                return false;
        }
    }
}
$ It\'s an IPhone

Type-testing Operators and Cast Expression

Implicit Casting

WildCat leopard = new WildCat();
Cat petCat = leopard;
// compile error
// WildCat wCat = petCat;  

Explicit Casting

WildCat wCat = (WildCat)petCat;

Avoiding Casting Exceptions

// WildCat wCat = (WildCat)petCat;
if (petCat is WildCat)
{
    Console.WriteLine($"{nameof(petCat)} IS an WildCat");
    WildCat wCat = (WildCat)petCat;
    // safely do something with wCat
}

is Operator

The is operator will check if the run-time type of an expression is compatible with a given type. The as operator considers only reference, nullable, boxing, and unboxing conversions.

if (petCat is WildCat)
{
}

as Operator

The as operator is used to explicitly convert an expression to a given type if its run-time type is compatible with that type. The as operator returns null if the conversion is not possible.

In MyBusiness/Program.cs,

using System;
using Animals;

// namespace
namespace MyBusiness
{
    // main program
    internal class Program
    {
        static void Main(string[] args)
        {
            // object is a base class of all derived classes in C#
            object[] myObjects = new object[4];
            myObjects[0] = new Dog();
            myObjects[1] = new Cat();
            myObjects[2] = "Dog";
            myObjects[3] = "Cat";

            for (int i = 0; i < myObjects.Length; i++)
            {
                // Convert an element in the myobjects array to a string element
                string? s = myObjects[i] as string;
                // Print out the current element
                Console.Write($"Inspecting element: {myObjects[i]}");

                // If converted successfully, s will be a string, otherwise return null.
                if (s == null)
                {
                    Console.Write(" --> Incompatible type");
                }
                else
                {
                    Console.Write(" --> Compatible type");
                }
                Console.WriteLine(", with string!");
            }
        }
    }
}

In PetLibrary/Animals.cs,

/*
The animal namespace
*/
namespace Animals
{
    public class Animal
    {
        public virtual void Speak()
        {
            Console.WriteLine("");
        }
    }

    public class Dog : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("Woof!");
        }
    }

    public class Cat : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("Meow!");
        }
    }
}

Environment.SpecialFolder Enum Doc

Other Interesting Types

  • System.Numerics (BigInteger, Complex, Quaternion)

Selected Theory

Updated: