C# 7.0 Notes

1. Why tuples?

– Want to return more than one value from method.
– Existing options available to developers are not optimal
– Introduced tuple types and tuple literals.
– Structs – value types
– Created locally and passed by copying contents
– Are mutable.

Trước tiên ta cần phải install một packet tên là System.ValueTuple như sau:

public class Chapter1
{
    public (int average, int studentCount) GetAverageAndCount(int[] scores)
    {
        // Khai báo thông thường
        // var returnTuple = (ave:0,sCount:0);
        // (int ave, int sCount) returnTuple;

        //Khai báo theo kiểu rút gọn luôn.
        (int ave, int sCount) returnTuple = (scores.Sum() / scores.Count(), scores.Count());
        return returnTuple;
    }

    public (double average, int studentCount, bool belowAverage) GetAverageAndCount(int[] scores, int threshold)
    {
        var returnTuple = (ave: 0D, sCount: 0, subAve: true);
        returnTuple = ((double)scores.Sum() / scores.Count(),
                        scores.Count(),
                        returnTuple.ave.checkIfBelowEverage(threshold));
        return returnTuple;
    }
}
public static class ExtensionMethods
{
    public static bool checkIfBelowEverage(this double classAverage, int threshold)
    {
        if (classAverage < threshold)
            return true;
        else
            return false;
    }

}

class Program
{
    static void Main(string[] args)
    {
        // Demo 1
        int[] scores = { 2, 2 };
        Chapter1 ch1 = new Chapter1();
        var (average, studentCount) = ch1.GetAverageAndCount(scores);
        WriteLine($"Average was {average} across {studentCount}");
        ReadLine();

        // Demo 2
        int[] scores = { 2, 2, 2, 2, 3 };
        Chapter1 ch1 = new Chapter1();
        int threshold = 51;
        var (average, studentCount, belowAverage) = ch1.GetAverageAndCount(scores, threshold);
        WriteLine(
            $"Average was {Round(average, 2)} across {studentCount} students. {(average < threshold ? " Class score below average." : " Class score above average.")}");
        ReadLine();
    }
}

Kết quả sẽ lần lượt là

2. Pattern matching

– Can test values in different ways
– Two language constructs have bene enhanced
– They are
  + Is expression 
  + Case clause in switch statements.
– Have pattern on right instead of type.
– Cause clause can now match on patterns
– No longer limited to primitive types.

namespace _2_Csharp_7_Pattern_Matching
{
    public class Chapter2
    {
        public void OutputInformation(object person)
        {
            // Nếu ta chỉ khai báo theo kiểu cũ như sau:
            // person is Student 
            // thì ta cần phải tạo ra một đối tượng sinh viên từ việc ép kiểu một person trước đó.
            // Điều này cũng tương tự cho Professor.

            if (person is Student student)
            { 
                //Student student = (Student) person;
                WriteLine($"Student {student.Name} {student.LastName} is enrolled for courses {String.Join<int>(", ", student.CourseCodes)}");
            }

            if (person is Professor prof)
            {
                //Professor prof = (Professor) person;
                WriteLine($"Professor {prof.Name} {prof.LastName} teaches  {String.Join<string>(",", prof.TeachesSubjects)}");
            }
        }

        public void OutputInformation2(object person)
        {
            switch (person)
            {
                case Student student when (student.CourseCodes.Contains(2)):
                    WriteLine($"Student {student.Name} {student.LastName} is enrolled for course 2.");
                    break;
                case Student student:
                    WriteLine($"Student {student.Name} {student.LastName} is enrolled for course {string.Join<int>(",", student.CourseCodes)}");
                    break;
                case Professor prof:
                    WriteLine($"Professor {prof.Name} {prof.LastName} teaches {string.Join<string>(",",prof.TeachesSubjects)}");
                    break;
                case null:
                    WriteLine($"Object {nameof(person) is null}");
                    break;
                default:
                    WriteLine("Unknown object detected");
                    break;

            }
        }
    }
      
    public class Student
    {
        public string Name { get; set; }
        public string LastName { get; set; }
        public List<int> CourseCodes { get; set; }

    }

    public class Professor
    {
        public string Name { get; set; }
        public string LastName { get; set; }
        public List<string> TeachesSubjects { get; set; }
    }
}

namespace _2_Csharp_7_Pattern_Matching
{
    // SCENARIO
    // Two object types:
    //      Student
    //      Professor
    // Minimize code
    // Create single method to output data from object passed to it
    // Method needs to figure out which object it is work.

    class Program
    {
        static void Main(string[] args)
        {
            Chapter2 ch2 = new Chapter2();
            Student student = new Student();
            student.Name = "Dirk";
            student.LastName = "Strauss";
            student.CourseCodes = new List<int>{3,2,5};
            ch2.OutputInformation(student);

            Professor prof = new Professor();
            prof.Name = "Reinhardt";
            prof.LastName = "Botha";
            prof.TeachesSubjects = new List<string>{"A","B"};
            ch2.OutputInformation(prof);
            ReadLine();
        }
    }
}

3. Out Variables

TryParse
– Method that tests to see if a value parse to specific type.
– If yes – returns a boolean value of true.

// Đoạn code sau sẽ giúp ta kiểm tra
// xem liệu rằng sValue có phải là một 
// string có thể chuyển thành kiểu int
// được hay không, khi ta sử dụng TryParse
// sẽ không văng exception khi không convert được
// mà thay vào đó nó chỉ trả về là false thôi.
int intVal;
if (int.TryParse(sValue, out intVal))
{
    WriteLine($"{intVal} is a valid integer");
    // Do something with intVal
}

// Ngoài ra ta còn có thể xem thêm
// Các cách sử dụng của TryParse như bên dưới
#region New out variable implementation
if (int.TryParse(sValue, out int intVal))
{
    WriteLine($"{intVal} is a valid integer");
    // Do something with intVal
}
 
if (int.TryParse(sValue, out var intVal))
{
    WriteLine($"{intVal} is a valid integer");
    // Do something with intVal
}
 
var (original, intVal, isInteger) = sValue.ToInt();
if (isInteger)
{
    WriteLine($"{original} is a valid integer");
    // Do something with intVal
}
#endregion

4.Deconstruction

– Tuples can be consumed
– Simply splits tuple into individual parts
– Assigns parts to new variables
– Not only reserved for tuples
– Ensure that type has deconstructor method

Để hiểu được cách sử dụng ta xét đoạn code sau:

public class Student
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public List<int> CourseCodes { get; set; }
    // Định nghĩa Deconstruct
    public void Deconstruct(out string name, out string lastName)
    {
        name = Name;
        lastName = LastName;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Student student = new Student();
        student.Name = "Tim";
        student.LastName = "Nguyen";
        // Gọi ra sử dụng deconstuct
        var (FirstName, Surname) = student;
        WriteLine($"The student name is {FirstName} {Surname}");
        ReadLine();
    }
}

Khi ta chạy chương trình ta sẽ được kết quả như sau:

Deconstuction còn dễ dàng được sử dụng thông ma một tín năng của C# gọi là Extension method như sau:

public class Student
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public List<int> CourseCodes { get; set; }
}
 
public static class ExtensionMethodClass
{
    public static void Deconstruct(
        this Student student, 
        out string firstItem, 
        out string secondItem) 
    {
        firstItem = student.Name;
        secondItem = student.LastName;
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Student student = new Student();
        student.Name = "Tim";
        student.LastName = "Nguyen";
        // Gọi ra sử dụng deconstuct
        var (FirstName, Surname) = student;
        WriteLine($"The student name is {FirstName} {Surname}");
        ReadLine();
    }
}

Khi ta chạy đoạn chương trình mà implement theo cách extension method ta cũng nhận được kết quả tương tự

5. Local Functions