C# Part 7 – Files and Directories, Databases

C# offers several methods to accomplish this task, depending on the nature of the data and the specific requirements of the application. It provides in-memory data storage options through collections and data structures. Lists, dictionaries, and arrays can store data during an application’s runtime, allowing for fast and flexible data access.

For more information about the various types of collections in C#, please read here.

For simple data storage needs or configuration settings, C# supports file-based methods. Developers can work with various file formats, such as XML, JSON, binary data, or plain text, to store and retrieve data. This is particularly useful for scenarios like user preferences or application settings.

The most common approach is to use databases, where C# integrates seamlessly with technologies like ADO.NET, Entity Framework, and LINQ to SQL. These frameworks allow developers to interact with databases efficiently, enabling the storage and retrieval of structured data.

C# Data Storage

Working with Files and Directories in C#

C# offers a robust set of classes and methods within the System.IO namespace that simplifies file and directory operations. Developers can easily create, read, write, and delete files and directories, making tasks such as file manipulation, data storage, and configuration management straightforward. The FileInfo and DirectoryInfo classes provide convenient ways to access file and directory properties and perform operations like moving, copying, or renaming.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        // Specify a directory path
        string directoryPath = @"C:\Temp\ExampleDirectory";

        try
        {
            // Create a directory
            DirectoryInfo directory = new DirectoryInfo(directoryPath);
            if (!Directory.Exists(directoryPath))
            {
                directory.Create();
                Console.WriteLine("Directory created successfully.");
            }

            // Create a text file in the directory
            string filePath = Path.Combine(directoryPath, "example.txt");
            File.WriteAllText(filePath, "This is a sample text file content.");
            Console.WriteLine("File created successfully.");

            // Search for files in the directory
            FileInfo[] files = directory.GetFiles("*.txt");

            Console.WriteLine("Files found in the directory:");
            foreach (FileInfo file in files)
            {
                Console.WriteLine(file.FullName);
            }

            // Delete the file
            File.Delete(filePath);
            Console.WriteLine("File deleted successfully.");

            // Delete the directory and its contents
            directory.Delete(true);
            Console.WriteLine("Directory and its contents deleted successfully.");

            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine("An error occurred: " + ex.Message);
        }
    }
}

Working with Databases in C#

The use of databases is beyond the scope of this guide. We will briefly introduce the various options and provide some resources.

Using ADO.NET in C#

ADO.NET provides a set of classes and libraries that allow developers to establish connections to databases, execute SQL commands, retrieve and manipulate data, and manage database transactions.

The core components of ADO.NET include the SqlConnection for database connections, SqlCommand for executing SQL queries, and SqlDataReader for reading data from query results.

ADO.NET also offers more high-level abstractions like the DataSet and DataAdapter for handling disconnected data, making it easier to work with data in memory before saving it back to the database.

Developers can connect to various database systems, such as SQL Server, MySQL, or Oracle, and efficiently manage data operations in C# applications, ensuring data integrity and scalability.

For more information about using ADO.NET, please refer to Microsoft Learn.

Using Entity Framework in C#

Using Entity Framework in C# is a powerful and efficient way to interact with databases and manage data within applications. Entity Framework is an Object-Relational Mapping (ORM) framework that abstracts the underlying database structure and allows developers to work with database entities as .NET objects.

This simplifies data access and manipulation by eliminating the need for complex SQL queries and direct database interactions. Developers can define data models using C# classes, and Entity Framework handles the translation between these objects and the database tables.

It supports various database providers, such as SQL Server, MySQL, and SQLite, making it versatile for different application scenarios. Entity Framework also facilitates features like data validation, change tracking, and lazy loading, enhancing productivity and code maintainability.

For more information about using Entity Framework, please refer to Microsoft Learn.

Using LINQ to SQL in C#

LINQ to SQL is an Object-Relational Mapping (ORM) framework that seamlessly integrates with C# and allows developers to query and manipulate database data using LINQ (Language-Integrated Query) expressions.

It simplifies the process of working with databases by allowing developers to write queries using C# language constructs, rather than crafting complex SQL statements. LINQ to SQL generates efficient SQL queries behind the scenes and automatically maps the results to C# objects, providing a seamless data access experience.

Developers can define data models as C# classes, annotating them with attributes to map them to database tables. This approach not only streamlines data operations but also enhances code maintainability.

LINQ to SQL supports various database providers, including SQL Server, making it a valuable tool for C# developers looking for a straightforward and efficient way to manage database interactions within their applications.

For more information about using LINQ to SQL, please refer to Microsoft Learn.

LINQ (Language Integrated Query) in C#

LINQ, which stands for Language-Integrated Query, is a powerful feature in C# that enables developers to perform queries on collections of data using a syntax that closely resembles SQL. With LINQ, you can filter, project, sort, and manipulate data in a more readable and expressive way.

It allows you to work with various data sources, including arrays, lists, databases, and XML, by providing a consistent querying mechanism. LINQ expressions typically consist of a series of operations, such as Where, Select, OrderBy, and GroupBy, which allow you to retrieve specific data subsets or transform data easily.

Querying data with LINQ in C#

LINQ allows developers to craft queries using a syntax that closely resembles SQL, making it intuitive and easy to use. Whether you’re working with in-memory data structures like arrays and lists or external data sources like databases or XML files, LINQ provides a unified querying mechanism. You can filter data with the Where clause, project data with Select, perform ordering with OrderBy, and even group data with GroupBy, among other operations.

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        // Sample data - an array of integers
        int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // LINQ query to retrieve even numbers
        var evenNumbers = from num in numbers
                          where num % 2 == 0
                          select num;

        // Display the even numbers
        Console.WriteLine("Even numbers:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }
        Console.ReadLine();
    }
}

Lambda expressions in C#

Lambda expressions provide a compact syntax for writing small, inline methods or expressions without the need to declare a separate named method. Lambda expressions are particularly useful when working with LINQ queries, event handlers, or other scenarios where a short, specialized function is required.

The syntax consists of the => (arrow) operator, which separates the input parameters from the expression body. Lambdas can capture variables from their enclosing scope, making them versatile for creating closures. They promote cleaner and more readable code, as developers can define functions at the point where they are needed, reducing the clutter of named methods.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of numbers
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // Use a Lambda expression with LINQ to select even numbers
        var evenNumbers = numbers.Where(n => n % 2 == 0);

        // Display the even numbers
        Console.WriteLine("Even numbers:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }
        Console.ReadLine();
    }
}

Chaining queries in C#

Chaining queries is a powerful technique that allows developers to string together multiple LINQ operations, creating a sequence of data transformations and filters in a concise and readable manner.

This approach, known as method chaining, is made possible by LINQ’s fluent syntax, where each LINQ method returns a new sequence that can be further manipulated with subsequent methods. Developers can sequentially apply Where clauses to filter data, Select clauses to project data, and OrderBy or GroupBy clauses to sort or group data—all in a single, fluid sequence.

Chaining queries not only simplifies code but also enhances its clarity by breaking down complex data operations into a series of easily understandable steps. It encourages a more functional and declarative style of programming, promoting clean and maintainable code while facilitating the transformation and querying of data across various C# applications and scenarios.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of integers
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // Chaining queries to filter and project data
        var result = numbers
            .Where(n => n % 2 == 0)      // Filter for even numbers
            .OrderByDescending(n => n)   // Sort in descending order
            .Select(n => n * 2);         // Double each number

        // Display the result
        Console.WriteLine("Filtered, sorted, and projected numbers:");
        foreach (var num in result)
        {
            Console.WriteLine(num);
        }
        Console.ReadLine();
    }
}

Transforming Data into New Types

Converting data from one format or structure into another, can be achieved through various means, such as creating custom data structures or using features like inheritance and interfaces to define new types.

Additionally, data transformation often involves mapping data from external sources, such as databases or APIs, into objects or classes within the C# application, making it more accessible and usable. This process enhances code organization, readability, and maintainability, ensuring that the data is presented in a way that aligns with the application’s logic and goals.

using System;
using System.Linq;
using System.Collections.Generic;

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Program
{
    static void Main()
    {
        // Sample data - a list of names
        List<string> names = new List<string> { "John Doe", "Jane Smith", "Mike Johnson" };

        // Transform names into Person objects using LINQ
        var people = names.Select(name =>
        {
            string[] parts = name.Split(' ');
            return new Person
            {
                FirstName = parts[0],
                LastName = parts[1]
            };
        });

        // Display the transformed data
        Console.WriteLine("Transformed data:");
        foreach (var person in people)
        {
            Console.WriteLine($"First Name: {person.FirstName}, Last Name: {person.LastName}");
        }
        Console.ReadLine();
    }
}

Querying collections Using LINQ in C#

Querying collections typically involves using various techniques and methods to filter, sort, project, or aggregate data stored in arrays, lists, dictionaries, or other data structures.

This process enables developers to retrieve specific elements or information from a collection based on certain criteria, such as searching for specific values, applying conditions, or transforming data into a desired format.

The ability to query collections efficiently is essential for tasks like data analysis, report generation, and data-driven decision-making. In C#, LINQ (Language-Integrated Query) provides a powerful and expressive way to query collections, making it easier to work with data and enhancing code readability and maintainability.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - collections of different types
        int[] numbers = { 1, 2, 3, 4, 5 };
        List<string> names = new List<string> { "Alice", "Bob", "Charlie", "David", "Eve" };
        Dictionary<int, string> keyValuePairs = new Dictionary<int, string>
        {
            { 1, "One" },
            { 2, "Two" },
            { 3, "Three" },
            { 4, "Four" },
            { 5, "Five" }
        };

        // Querying an array
        var evenNumbers = numbers.Where(n => n % 2 == 0);

        // Querying a list
        var longNames = names.Where(name => name.Length > 4);

        // Querying a dictionary
        var keyGreaterThanTwo = keyValuePairs.Where(pair => pair.Key > 2);

        // Display the results
        Console.WriteLine("Even numbers:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }

        Console.WriteLine("\nLong names:");
        foreach (var name in longNames)
        {
            Console.WriteLine(name);
        }

        Console.WriteLine("\nKey-Value pairs with keys greater than 2:");
        foreach (var pair in keyGreaterThanTwo)
        {
            Console.WriteLine($"Key: {pair.Key}, Value: {pair.Value}");
        }
        Console.ReadLine();
    }
}

LINQ to Objects in C#

LINQ to Objects in C# is a versatile and user-friendly tool for querying and manipulating in-memory collections of data. It simplifies the process of working with arrays, lists, dictionaries, and other enumerable objects by offering a consistent query syntax that resembles SQL.

Developers can use LINQ to perform various operations such as filtering, sorting, projecting, and aggregating data without the need for complex loops or manual iteration. This approach not only streamlines code but also enhances its readability and maintainability. LINQ to Objects promotes a more declarative and functional style of programming, enabling developers to express their intentions clearly and concisely when working with data.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of numbers
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // Use LINQ to filter even numbers
        var evenNumbers = numbers.Where(num => num % 2 == 0);

        // Use LINQ to calculate the sum of even numbers
        int sumOfEvens = evenNumbers.Sum();

        // Display the filtered numbers and their sum
        Console.WriteLine("Even numbers:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }

        Console.WriteLine("Sum of even numbers: " + sumOfEvens);
        Console.ReadLine();
    }
}

Filtering data with LINQ in C#

LINQ provides a standardized query syntax that closely resembles SQL, making it easier to express complex filtering conditions in a readable and concise manner. Developers can use LINQ’s Where clause to filter data by specifying conditions or predicates, ensuring that only the desired elements meet the criteria.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of products
        List<Product> products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Price = 800 },
            new Product { Id = 2, Name = "Phone", Price = 500 },
            new Product { Id = 3, Name = "Tablet", Price = 300 },
            new Product { Id = 4, Name = "Monitor", Price = 250 },
            new Product { Id = 5, Name = "Keyboard", Price = 50 }
        };

        // Filtering products by price
        var affordableProducts = products.Where(p => p.Price < 300);

        // Filtering products by name
        var nameContainsL = products.Where(p => p.Name.Contains("L"));

        // Filtering products by a combination of conditions
        var filteredProducts = products.Where(p => p.Price < 300 && p.Name.Contains("M"));

        // Display the filtered products
        Console.WriteLine("Affordable Products:");
        foreach (var product in affordableProducts)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }

        Console.WriteLine("\nProducts with 'L' in the name:");
        foreach (var product in nameContainsL)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }

        Console.WriteLine("\nFiltered Products:");
        foreach (var product in filteredProducts)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }
        Console.ReadLine();
    }
}

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Projecting Data with LINQ in C#

Projecting data developers to create new representations of data by selecting specific properties or applying computations to existing values. LINQ provides the Select clause, which serves as a powerful tool for projecting data.

With LINQ, developers can extract just the relevant information they need from a collection or other data source, making it easier to work with and reducing the complexity of code. Whether it’s mapping database records to custom objects, extracting specific fields from a dataset, or calculating derived values, projecting data with LINQ enhances the flexibility and expressiveness of C# code.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of products
        List<Product> products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Price = 800 },
            new Product { Id = 2, Name = "Phone", Price = 500 },
            new Product { Id = 3, Name = "Tablet", Price = 300 },
            new Product { Id = 4, Name = "Monitor", Price = 250 },
            new Product { Id = 5, Name = "Keyboard", Price = 50 }
        };

        // Projecting product names
        var productNames = products.Select(p => p.Name);

        // Projecting product names with prices
        var productNamesWithPrices = products.Select(p => $"{p.Name} - ${p.Price}");

        // Projecting products with reduced prices
        var productsWithReducedPrices = products.Select(p =>
        {
            p.Price -= 50; // Reduce the price by $50
            return p;
        });

        // Display the projected data
        Console.WriteLine("Product Names:");
        foreach (var name in productNames)
        {
            Console.WriteLine(name);
        }

        Console.WriteLine("\nProduct Names with Prices:");
        foreach (var nameWithPrice in productNamesWithPrices)
        {
            Console.WriteLine(nameWithPrice);
        }

        Console.WriteLine("\nProducts with Reduced Prices:");
        foreach (var product in productsWithReducedPrices)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }
        Console.ReadLine();
    }
}

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Ordering Data with LINQ in C#

LINQ provides the OrderBy and OrderByDescending clauses, enabling ascending and descending sorting based on one or more criteria. This functionality is crucial for scenarios where data needs to be presented in an organized manner, whether for display to users, generation of reports, or further data processing.

By utilizing LINQ for data ordering, developers can streamline the sorting process, eliminating the need for custom sorting algorithms and complex code. Additionally, LINQ allows for sorting by multiple properties, providing flexibility and precision in arranging data.

using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
    static void Main()
    {
        // Sample data - a list of products
        List<Product> products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Price = 800 },
            new Product { Id = 2, Name = "Phone", Price = 500 },
            new Product { Id = 3, Name = "Tablet", Price = 300 },
            new Product { Id = 4, Name = "Monitor", Price = 150 },
            new Product { Id = 5, Name = "Keyboard", Price = 70 },
            new Product { Id = 6, Name = "Monitor", Price = 250 },
            new Product { Id = 7, Name = "Keyboard", Price = 50 }
        };

        // Order products by name in ascending order
        var productsByName = products.OrderBy(p => p.Name);

        // Order products by price in descending order
        var productsByPriceDesc = products.OrderByDescending(p => p.Price);

        // Order products by name in ascending order, then by price in descending order
        var productsByNameAndPrice = products.OrderBy(p => p.Name).ThenByDescending(p => p.Price);

        // Display the ordered data
        Console.WriteLine("Products ordered by name:");
        foreach (var product in productsByName)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }

        Console.WriteLine("\nProducts ordered by price in descending order:");
        foreach (var product in productsByPriceDesc)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }

        Console.WriteLine("\nProducts ordered by name, then by price:");
        foreach (var product in productsByNameAndPrice)
        {
            Console.WriteLine($"{product.Name} - ${product.Price}");
        }
        Console.ReadLine();
    }
}

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Grouping Data with LINQ in C#

LINQ provides the GroupBy clause, which enables developers to group data into sets or collections, essentially creating a hierarchical structure within the original data. This is particularly valuable when working with large datasets or when data needs to be presented in a way that facilitates analysis or reporting.

By grouping data, developers can perform aggregate operations, compute summaries, or create nested structures that represent relationships between data elements. Grouping with LINQ enhances code clarity and enables developers to express complex data relationships in a more intuitive and straightforward manner.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - a list of products
        List<Product> products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Category = "Electronics" },
            new Product { Id = 2, Name = "Phone", Category = "Electronics" },
            new Product { Id = 3, Name = "Tablet", Category = "Electronics" },
            new Product { Id = 4, Name = "Shirt", Category = "Clothing" },
            new Product { Id = 5, Name = "Jeans", Category = "Clothing" },
            new Product { Id = 6, Name = "Headphones", Category = "Electronics" },
        };

        // Group products by category
        var productsByCategory = products.GroupBy(p => p.Category);

        // Display the grouped data
        Console.WriteLine("Products grouped by category:");
        foreach (var group in productsByCategory)
        {
            Console.WriteLine($"Category: {group.Key}");
            foreach (var product in group)
            {
                Console.WriteLine($"- {product.Name}");
            }
        }
        Console.ReadLine();
    }
}

class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
}

Joining Data with LINQ in C#

LINQ provides the join clause, which enables the creation of relationships between data collections, such as databases, lists, or arrays, and then retrieves data from those collections that match specified conditions.

This process is particularly valuable when working with relational or structured data, as it allows for the retrieval of data from multiple sources with intricate relationships. Developers can perform various types of joins, including inner, outer, left, and right joins, to obtain the exact data they need.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Sample data - lists of students and their courses
        List<Student> students = new List<Student>
        {
            new Student { StudentId = 1, Name = "Alice" },
            new Student { StudentId = 2, Name = "Bob" },
            new Student { StudentId = 3, Name = "Charlie" },
        };

        List<Course> courses = new List<Course>
        {
            new Course { CourseId = 101, Title = "Math", StudentId = 1 },
            new Course { CourseId = 102, Title = "History", StudentId = 2 },
            new Course { CourseId = 103, Title = "Science", StudentId = 1 },
            new Course { CourseId = 104, Title = "English", StudentId = 3 },
        };

        // Inner join students with courses
        var innerJoin = from student in students
                        join course in courses on student.StudentId equals course.StudentId
                        select new { student.Name, course.Title };

        // Left join students with courses
        var leftJoin = from student in students
                       join course in courses on student.StudentId equals course.StudentId into courseGroup
                       from cg in courseGroup.DefaultIfEmpty()
                       select new { student.Name, CourseTitle = cg?.Title ?? "No Course" };

        // Display the results
        Console.WriteLine("Inner Join:");
        foreach (var result in innerJoin)
        {
            Console.WriteLine($"{result.Name} - {result.Title}");
        }

        Console.WriteLine("\nLeft Join:");
        foreach (var result in leftJoin)
        {
            Console.WriteLine($"{result.Name} - {result.CourseTitle}");
        }
        Console.ReadLine();
    }
}

class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }
}

class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; }
    public int StudentId { get; set; }
}

Code Example Note

The expression CourseTitle = cg?.Title ?? “No Course” is a combination of two operators, the null-conditional operator (?.) and the null-coalescing operator (??).

cg?.Title: This part uses the null-conditional operator (?.). It’s used to access the Title property of the object referred to by the variable cg. However, it does so in a way that if cg is null, it won’t throw a null reference exception but instead will result in a null value. So, if cg is not null, cg?.Title returns the value of the Title property; if cg is null, it returns null.

?? “No Course”: This part uses the null-coalescing operator (??). It’s used to provide a default value in case the expression on its left side (in this case, cg?.Title) evaluates to null. If the left side is not null, it will use the value from the left side; otherwise, it will use the value on the right side, which is “No Course” in this case.

So, in the context of the LINQ query from the previous example, CourseTitle = cg?.Title ?? “No Course” ensures that CourseTitle will be assigned the title of a course if available (not null), and if the course doesn’t exist or if the cg object is null (indicating no course for that student), it will default to “No Course.” This helps handle potential null values gracefully and provides a fallback value for cases where data may be missing or incomplete.

LINQ to XML in C#

LINQ to XML provides a convenient and expressive way to create, read, update, and transform XML documents within C# applications. With LINQ to XML, developers can represent XML data as hierarchical collections of strongly-typed objects, making it easier to work with XML in an object-oriented manner.

This technology enables the creation of XML documents, parsing of XML from various sources, and efficient querying of XML data using LINQ queries. Developers can filter, transform, and extract information from XML documents with ease, resulting in more readable and maintainable code.

LINQ to XML is particularly valuable when dealing with XML-based data formats such as configuration files, web services, or data interchange, allowing developers to handle XML data seamlessly and efficiently within their C# applications.

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        // Sample XML data as a string
        string xmlData = @"
            <Books>
                <Book>
                    <Title>Introduction to C#</Title>
                    <Author>John Doe</Author>
                </Book>
                <Book>
                    <Title>Programming with LINQ</Title>
                    <Author>Jane Smith</Author>
                </Book>
                <Book>
                    <Title>Mastering XML</Title>
                    <Author>Mike Johnson</Author>
                </Book>
            </Books>";

        // Parse the XML data
        XDocument xmlDoc = XDocument.Parse(xmlData);

        // Query and extract book titles using LINQ to XML
        var bookTitles = from book in xmlDoc.Descendants("Book")
                         select book.Element("Title").Value;

        // Display the extracted book titles
        Console.WriteLine("Book Titles:");
        foreach (var title in bookTitles)
        {
            Console.WriteLine(title);
        }
        Console.ReadLine();

    }
}