[In-depth C#] Chapter 5: Advanced Object-Oriented Programming: Generic Programming and Collection Types

Advanced object-oriented programming is a programming paradigm that is further deepened and expanded on the basis of basic object-oriented programming. It emphasizes the concepts of encapsulation, inheritance, and polymorphism, and introduces advanced features such as generic programming and collection types. Advanced object-oriented programming provides a more flexible, extensible and reusable code structure, which can help developers build more complex and efficient applications. In advanced object-oriented programming, generic programming makes the code more general and flexible, and can handle different types of data without repeating similar code. Collection types provide rich data structures and algorithms, making data management and operations more convenient and efficient.
By deeply understanding and applying advanced object-oriented programming concepts and features, developers can design more reliable, maintainable, and extensible software systems. This programming paradigm plays an important role in modern software development, providing developers with powerful tools and mindsets to better meet changing needs and challenges.

1. The concept and function of generic programming

1.1 Definition and characteristics of generics

Generics are a feature introduced in programming languages ​​that allow the use of type parameters when defining classes, interfaces, methods, etc., allowing for generality and flexibility of code. Through generics, you can write code that can be applied to multiple types without repeating similar code logic.
Key features of generics include:

  1. Type parameterization: Generics allow the use of type parameters at definition time, which defers specific type information until use time, making the code more general.
  2. Type safety: Generics are type checked at compile time, and type errors can be caught at compile time to avoid type mismatch errors at runtime.
  3. Code reusability: Through generics, you can write common codes suitable for different types, avoiding repeated writing of similar code logic.
  4. Performance optimization: Generics generate specialized codes for specific types at compile time, thereby improving execution efficiency and avoiding overheads such as boxing and unboxing.
  5. Scalability: Generics allow specific type parameters to be specified when used, so that the code can adapt to different data types and has high scalability.
1.2 Advantages and Application Scenarios of Generics

Generics have many advantages and application scenarios in programming, including:

  1. Code reuse and versatility: Generics allow the writing of general-purpose code, which can be applied to multiple data types, avoiding repetitive writing of similar code logic, and improving code reusability.
  2. Type safety and reliability: Generics perform type checking at compile time, which can catch type errors at compile time, reduce type-related errors at runtime, and improve code reliability.
  3. Performance optimization: Generics generate specialized code for specific types at compile time, avoiding boxing and unboxing overhead, and improving code execution efficiency.
  4. Implementation of data structures and algorithms: Generics are widely used in the implementation of data structures and algorithms. It is easy to create data structures and algorithms applicable to different types, which improves the scalability and flexibility of the code.
  5. Collection classes and container classes: Generics enable collection classes and container classes to store and manipulate different types of data, providing more flexible and general data management tools.
  6. Use of interfaces and delegates: Generics can be used in conjunction with interfaces and delegates to make code more flexible and extensible, providing a more powerful programming model.

Generics have a wide range of application scenarios, especially in scenarios where multiple data types need to be processed, such as data structures, algorithm implementations, collection classes and container classes, database operations, etc. By properly applying generics, code reusability, maintainability, and performance can be improved while reducing development complexity.

1.3 Declaration and use of generic types and methods

The declaration and use of generic types and methods can be achieved by:

  1. Declaration and use of generic types:
// 声明泛型类
class MyGenericClass<T>
{
    
    
    private T myField;

    public MyGenericClass(T value)
    {
    
    
        myField = value;
    }

    public T MyMethod()
    {
    
    
        return myField;
    }
}

// 使用泛型类
MyGenericClass<int> intObj = new MyGenericClass<int>(10);
int value = intObj.MyMethod();  // 返回整数类型

MyGenericClass<string> stringObj = new MyGenericClass<string>("Hello");
string text = stringObj.MyMethod();  // 返回字符串类型
  1. Declaration and use of generic methods:
// 声明泛型方法
class MyGenericClass
{
    
    
    public T MyMethod<T>(T value)
    {
    
    
        return value;
    }
}

// 使用泛型方法
MyGenericClass myObj = new MyGenericClass();
int intValue = myObj.MyMethod(10);  // 返回整数类型

string stringValue = myObj.MyMethod("Hello");  // 返回字符串类型

2. The concept and classification of collection types

2.1 Definition and function of collection type

Collection types are data structures used to store and manipulate a group of related data. They provide convenient methods to add, remove, access and search elements in the collection. In C#, common collection types include arrays, lists, dictionaries, collections, and queues.
The functions of collection types include:

  1. Storing and organizing data: Collection types provide an efficient way to store and organize large amounts of data, making it easy to access and manage.
  2. Provide efficient data operations: Collection types provide various methods and operators to perform common data operations, such as search, insert, delete, and sort, etc., in order to process data more conveniently.
  3. Supports dynamic size: Unlike arrays, collection types can be dynamically resized as needed to accommodate varying numbers of elements.
  4. Provide type safety: The collection type can specify to store specific types of elements, thereby providing type safety and preventing wrong data types from being added to the collection.
  5. Implement specific data structures: Different types of collections can implement different data structures, such as lists, dictionaries, stacks, and queues, to meet different data manipulation requirements.

By choosing an appropriate collection type, you can organize and process data more efficiently, improving the readability and maintainability of your code. They are used in a wide variety of applications, including areas such as data processing, algorithm implementation, user interface, and network programming.

2.2 Common Collection Types
  1. Array (Array):

    • Definition syntax: T[] arrayName;(where T is the element type)
    • Create an array:T[] arrayName = new T[length];
    • access element:arrayName[index]
    • Example:
      int[] numbers = new int[5];
      numbers[0] = 1;
      numbers[1] = 2;
      // ...
      
  2. List (List):

    • Definition syntax: List<T> listName = new List<T>();(where T is the element type)
    • Add element:listName.Add(element);
    • access element:listName[index]
    • Example:
      List<string> names = new List<string>();
      names.Add("Alice");
      names.Add("Bob");
      // ...
      
  3. Dictionary:

    • Definition syntax: Dictionary<TKey, TValue> dictionaryName = new Dictionary<TKey, TValue>();(where TKey is the key type and TValue is the value type)
    • Add key-value pairs:dictionaryName.Add(key, value);
    • access value:dictionaryName[key]
    • Example:
      Dictionary<int, string> ages = new Dictionary<int, string>();
      ages.Add(1, "Alice");
      ages.Add(2, "Bob");
      // ...
      
  4. Collection (Set):

    • Definition syntax: HashSet<T> setName = new HashSet<T>();(where T is the element type)
    • Add element:setName.Add(element);
    • Check if element exists:setName.Contains(element)
    • Example:
      HashSet<string> uniqueNames = new HashSet<string>();
      uniqueNames.Add("Alice");
      uniqueNames.Add("Bob");
      // ...
      
  5. Queue:

    • Definition syntax: Queue<T> queueName = new Queue<T>();(where T is the element type)
    • Enqueue:queueName.Enqueue(element);
    • Dequeue:queueName.Dequeue()
    • Example:
      Queue<int> numbers = new Queue<int>();
      numbers.Enqueue(1);
      numbers.Enqueue(2);
      // ...
      
2.3 Characteristics and usage scenarios of collection types

Collection types have the following characteristics and usage scenarios:

  1. Array (Array):

    • Features: It has a fixed length and can directly access elements through indexes.
    • Usage scenario: Suitable for situations where the length is known and fast random access to elements is required.
  2. List (List):

    • Features: It can be dynamically adjusted in size and provides a wealth of operation methods (add, delete, search, etc.).
    • Usage scenario: It is suitable for situations where frequent insertion, deletion and traversal of elements are required.
  3. Dictionary:

    • Features: Use key-value pairs to store data, and quickly search through keys.
    • Usage scenario: Applicable to situations where you need to quickly find and access the corresponding value based on the key.
  4. Collection (Set):

    • Features: Store unique elements and provide efficient deduplication functions.
    • Usage scenario: Suitable for situations where you need to store unique elements, such as finding duplicates or creating unordered collections.
  5. Queue:

    • Features: The first-in-first-out (FIFO) data structure supports adding elements at the end of the queue and removing elements at the head of the queue.
    • Usage scenario: Applicable to situations where elements need to be processed in sequence, such as task scheduling, message processing, etc.

Each collection type has its unique characteristics and applicable scenarios. Choosing the appropriate collection type according to actual needs can improve the efficiency and readability of the program.

Third, the use of collection types

3.1 Common operations and methods of collection types

The following are common operations and methods for arrays, lists, dictionaries, sets, and queues, as well as corresponding case examples:

  1. Array (Array):

    • Accessing elements: Array elements are accessed using an index.
    • Get Length: Use the Length property to get the length of the array.
    • Traversing an Array: Use a for loop or a foreach loop to iterate through an array.

    Example:

    int[] numbers = {
          
           1, 2, 3, 4, 5 };
    int firstElement = numbers[0];
    int length = numbers.Length;
    for (int i = 0; i < numbers.Length; i++)
    {
          
          
        Console.WriteLine(numbers[i]);
    }
    
  2. List (List):

    • Adding elements: Use the Add method to add elements to the list.
    • Remove elements: Use the Remove method to remove elements from the list.
    • Find elements: Use the Contains method to determine whether a list contains an element.

    Example:

    List<string> names = new List<string>();
    names.Add("Alice");
    names.Add("Bob");
    names.Remove("Alice");
    bool containsBob = names.Contains("Bob");
    
  3. Dictionary (Dictionary):

    • Add key-value pairs: Use the Add method to add key-value pairs.
    • Remove key-value pair: Use the Remove method to remove the key-value pair of the specified key.
    • Get the number of key-value pairs: Use the Count property to get the number of key-value pairs.

    Example:

    Dictionary<string, int> ages = new Dictionary<string, int>();
    ages.Add("Alice", 25);
    ages.Add("Bob", 30);
    ages.Remove("Alice");
    int count = ages.Count;
    
  4. Collection (Set):

    • Adding elements: Use the Add method to add elements to the collection.
    • Remove elements: Use the Remove method to remove elements from the collection.
    • Find elements: Use the Contains method to determine whether the collection contains an element.

    Example:

    HashSet<string> names = new HashSet<string>();
    names.Add("Alice");
    names.Add("Bob");
    names.Remove("Alice");
    bool containsBob = names.Contains("Bob");
    
  5. Queue (Queue):

    • Enqueue: Use the Enqueue method to add elements to the queue.
    • Dequeue: Use the Dequeue method to remove and return the first element from the queue.

    Example:

    Queue<int> queue = new Queue<int>();
    queue.Enqueue(1);
    queue.Enqueue(2);
    int firstElement = queue.Dequeue();
    
3.2 Traversal and element access of collection types

Here are the traversal and element access methods for arrays, lists, dictionaries, sets, and queues:

  1. Array (Array):

    • Traversal: use for loop or foreach loop to traverse array elements.
    • Element Access: Array elements are accessed using an index.

    Example:

    int[] numbers = {
          
           1, 2, 3, 4, 5 };
    for (int i = 0; i < numbers.Length; i++)
    {
          
          
        Console.WriteLine(numbers[i]);
    }
    
    foreach (int number in numbers)
    {
          
          
        Console.WriteLine(number);
    }
    
  2. List (List):

    • Traversal: use foreach loop to traverse list elements.
    • Element Access: List elements are accessed using an index.

    Example:

    List<string> names = new List<string>();
    names.Add("Alice");
    names.Add("Bob");
    foreach (string name in names)
    {
          
          
        Console.WriteLine(name);
    }
    
    string firstElement = names[0];
    
  3. Dictionary (Dictionary):

    • Traverse key-value pairs: use foreach loop to traverse the key-value pairs in the dictionary.
    • Element access: Use the key to access the value in the dictionary.

    Example:

    Dictionary<string, int> ages = new Dictionary<string, int>();
    ages.Add("Alice", 25);
    ages.Add("Bob", 30);
    foreach (KeyValuePair<string, int> pair in ages)
    {
          
          
        Console.WriteLine(pair.Key + ": " + pair.Value);
    }
    
    int aliceAge = ages["Alice"];
    
  4. Collection (Set):

    • Traversal: Use the foreach loop to traverse the collection elements.
    • Element access: The collection has no index, you can use the foreach loop to traverse the collection elements and access them.

    Example:

    HashSet<string> names = new HashSet<string>();
    names.Add("Alice");
    names.Add("Bob");
    foreach (string name in names)
    {
          
          
        Console.WriteLine(name);
    }
    
  5. Queue (Queue):

    • Traversal: The queue has no direct traversal method, it can be traversed by transferring the queue elements to other data structures.
    • Element access: Use the Peek method to get the head element of the queue.

    Example:

    Queue<int> queue = new Queue<int>();
    queue.Enqueue(1);
    queue.Enqueue(2);
    
    // 将队列元素转移到列表中进行遍历
    List<int> queueList = new List<int>(queue);
    foreach (int number in queueList)
    {
          
          
        Console.WriteLine(number);
    }
    
    int firstElement = queue.Peek();
    

4. Collection type iteration and LINQ query

4.1 Ways to iterate collection types and loop traversal

In C#, you can iterate and traverse collection types in different ways, including arrays, lists, dictionaries, sets, and queues. Here are some commonly used iteration and traversal methods:

  1. Use foreacha loop:

    • Applies to types that implement IEnumerableinterfaces such as arrays, lists, and collections.
    • Iterate over each element without concern for index or key.
    • Example:
      int[] numbers = {
              
               1, 2, 3, 4, 5 };
      foreach (int number in numbers)
      {
              
              
          Console.WriteLine(number);
      }
      
      List<string> names = new List<string>() {
              
               "Alice", "Bob", "Charlie" };
      foreach (string name in names)
      {
              
              
          Console.WriteLine(name);
      }
      
  2. Use fora loop:

    • Works with arrays or collection types with an index.
    • Need to focus on the index of the element.
    • Example:
      int[] numbers = {
              
               1, 2, 3, 4, 5 };
      for (int i = 0; i < numbers.Length; i++)
      {
              
              
          Console.WriteLine(numbers[i]);
      }
      
      List<string> names = new List<string>() {
              
               "Alice", "Bob", "Charlie" };
      for (int i = 0; i < names.Count; i++)
      {
              
              
          Console.WriteLine(names[i]);
      }
      
  3. Use an iterator ( IEnumeratoror IEnumerator<T>):

    • Useful when manual control over the iterative process is required.
    • You need to use MoveNext()methods to move to the next element and Currentproperties to get the current element.
    • Example:
      List<string> names = new List<string>() {
              
               "Alice", "Bob", "Charlie" };
      IEnumerator<string> enumerator = names.GetEnumerator();
      while (enumerator.MoveNext())
      {
              
              
          string name = enumerator.Current;
          Console.WriteLine(name);
      }
      

Either way, collection types can be iterated and traversed, accessing each element and performing the corresponding operation. Which method to choose depends on the collection type and specific needs.

4.2 The concept and basic usage of LINQ query

LINQ (Language Integrated Query) is a language-integrated query technology used in C# to query and manipulate data. It provides a unified syntax and way to query different types of data sources, such as collections, databases, XML, etc.

The basic usage is as follows:

  1. import-namespace: imports System.Linqa namespace at the top of the file.
  2. Create a data source: it can be a collection, an array, a database table, etc.
  3. Build query expressions: Build queries using LINQ query expressions. Expressions are similar to SQL statements and are used to specify query conditions, sorting methods, etc.
  4. Execute query: Use the methods provided by LINQ, such as ToList(), ToArray(), First()etc., to execute the query and return the result.

Sample code:

using System;
using System.Linq;

class Program
{
    
    
    static void Main()
    {
    
    
        // 创建数据源
        int[] numbers = {
    
     1, 2, 3, 4, 5 };

        // 构建查询表达式
        var evenNumbers = from number in numbers
                          where number % 2 == 0
                          select number;

        // 执行查询
        foreach (var number in evenNumbers)
        {
    
    
            Console.WriteLine(number);
        }
    }
}

numbersIn the above example, the even numbers in the array are filtered out through the LINQ query expression , and foreachthe result is output using a loop.

LINQ also supports other powerful features such as grouping, sorting, projection, etc. Through LINQ, a unified syntax can be used to process different types of data sources, which simplifies the process of querying and manipulating data, and improves the readability and maintainability of the code.

5. Sorting and comparison of collection types

5.1 Sorting methods and algorithms for collection types

The collection type provides a variety of sorting methods and algorithms in C#, and you can choose an appropriate way to sort according to your specific needs.

  1. Use Sort()the method: Collection types (such as lists) provide Sort()the method, which can directly sort the collection in place. By default, Sort()the method sorts using the natural order of the elements. If you need a custom collation, you can specify a comparator using a delegate or a Lambda expression.

    Sample code:

    List<int> numbers = new List<int> {
          
           5, 3, 1, 4, 2 };
    numbers.Sort(); // 默认按升序排序
    
  2. The method using LINQ OrderBy(): through the clause in the LINQ query expression orderby, the collection can be sorted. You can specify a sort order using ascendingthe or descendingkeywords, and use a property or expression as the sort key.

    Sample code:

    List<int> numbers = new List<int> {
          
           5, 3, 1, 4, 2 };
    var sortedNumbers = numbers.OrderBy(x => x); // 按升序排序
    
  3. ComparerCustom sorting using classes: ComparerClasses provide a variety of static methods that can be used to create custom comparators. You can implement IComparer<T>the interface or use Comparison<T>the delegate to define a custom comparator and pass it to the sort method.

    Sample code:

    List<int> numbers = new List<int> {
          
           5, 3, 1, 4, 2 };
    numbers.Sort((x, y) => y.CompareTo(x)); // 自定义降序排序
    
  4. Use LINQ OrderBy()methods and custom comparators: You can combine LINQ OrderBy()methods and custom comparators to implement complex sorting requirements. A custom comparator needs to implement IComparer<T>the interface and OrderBy()specify the comparator in the method.

    Sample code:

    List<int> numbers = new List<int> {
          
           5, 3, 1, 4, 2 };
    var sortedNumbers = numbers.OrderBy(x => x, new CustomComparer()); // 使用自定义比较器进行排序
    
5.2 Custom Comparators and Collations

In C#, collation can be defined by custom comparator. A comparator is a class that implements IComparer<T>the interface or Comparison<T>a method that uses the delegate to compare the size relationship of two objects.

Here is sample code for a custom comparator and collation:

// 定义自定义比较器实现 IComparer<T> 接口
public class CustomComparer : IComparer<int>
{
    
    
    public int Compare(int x, int y)
    {
    
    
        // 自定义排序规则:按绝对值大小进行排序
        int absX = Math.Abs(x);
        int absY = Math.Abs(y);
        return absX.CompareTo(absY);
    }
}

// 使用自定义比较器进行排序
List<int> numbers = new List<int> {
    
     -5, 3, -1, 4, -2 };
numbers.Sort(new CustomComparer());

// 输出排序结果
foreach (int number in numbers)
{
    
    
    Console.WriteLine(number);
}

In the above example, a CustomComparercustom comparator named is defined, IComparer<int>the interface is implemented, and Comparea custom sorting rule is defined in the method, which is to sort by absolute value. Then, use Sortthe method and pass in an instance of your custom comparator to sort the elements in the list.

By customizing the comparator, you can flexibly define sorting rules to meet specific sorting requirements. The size relationship of objects can be determined according to their attributes, fields or other custom logic, so as to realize the function of sorting by specific rules.

6. Performance and best practices of collection types

Performance and best practices for collection types are important factors to consider during development. Here are some recommendations for collection type performance and best practices:

  1. Select the appropriate collection type: Select the appropriate collection type according to specific needs. For example, if you need fast random access to elements, you can choose to use arrays or lists; if you need efficient search and insertion operations, you can choose to use dictionaries or sets, etc.
  2. Avoid frequent collection copying: Frequent copying operations on large collections can consume a lot of memory and time. Try to avoid unnecessary copying of collections, especially in loops.
  3. Use the correct data structure: Choose the appropriate data structure according to the specific data operation requirements. For example, if you need to do a quick lookup by key, using a dictionary will be more efficient than a list; if you need to maintain a sorted order, you can use a sorted collection, etc.
  4. Consider the size of the collection: For large datasets, consider using lazy loading or paginated loading to reduce memory consumption and improve performance.
  5. Use iterators instead of copying collections: Using iterators to traverse a collection avoids unnecessary copying of the collection, improving performance and memory efficiency.
  6. Pay attention to the thread safety of collections: When using collections in a multi-threaded environment, make sure to take appropriate thread safety measures, such as using locks or concurrent collections.
  7. Avoid frequent insertion and deletion operations: Some collection types have low performance when frequent insertion and deletion operations, consider using other more suitable collection types or optimization algorithms.
  8. Pay attention to memory management: release the collection in time when the collection is not needed to avoid memory leaks.

7. Summary

In advanced object-oriented programming, generic programming and collection types are important concepts and tools. Generics provide a generic way to create reusable and type-safe code, making code more flexible and extensible. Generic types and methods can use different data types as needed, improving code flexibility and performance.
Collection types are containers for storing and managing data, including arrays, lists, dictionaries, collections, and queues. They provide different functions and features, and you can choose the appropriate collection type according to your needs. The use of collection types involves operations such as adding, deleting, accessing, and sorting elements, and requires familiarity with the corresponding methods and algorithms.
We need to consider performance and best practices when working with collection types. Choosing the appropriate collection type, avoiding unnecessary collection copying, using the correct data structure, considering the size of the collection, using iterators, paying attention to thread safety, avoiding frequent insertion and deletion operations, etc. are all important factors for optimizing collection performance. At the same time, reasonable memory management and compliance with coding standards can also improve the quality and maintainability of the code.
By understanding and applying generic programming and collection types, we can better organize and manage data, improve code reusability and scalability, speed up development efficiency, and effectively solve complex problems.

Guess you like

Origin blog.csdn.net/gangzhucoll/article/details/131757462