Форум программистов, компьютерный форум, киберфорум
bytestream
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Версии C#, их отличия и нововведения

Запись от bytestream размещена 04.02.2025 в 15:16
Показов 688 Комментарии 0
Метки c#

Нажмите на изображение для увеличения
Название: 8e1955e2-5d4a-45a5-a210-0ee1426cf9d7.png
Просмотров: 33
Размер:	2.27 Мб
ID:	9656
Язык программирования C# прошел длительный путь эволюции от своего первоначального выпуска в 2002 году до современной версии. За это время было выпущено множество значительных обновлений, каждое из которых привносило новые возможности и улучшения в язык. Каждая версия C# разрабатывалась с учетом потребностей разработчиков и современных тенденций в программировании, что сделало его одним из наиболее мощных и гибких языков программирования.

Платформа .NET и язык C# развивались параллельно, обеспечивая разработчиков инструментами для создания все более сложных и эффективных приложений. Важной особенностью развития C# является сохранение обратной совместимости при добавлении новых возможностей. Это означает, что код, написанный на ранних версиях языка, продолжает работать в более новых версиях, что особенно важно для поддержки существующих проектов.

Эволюция языка включает в себя множество значительных изменений: от базовых конструкций и синтаксического сахара до сложных механизмов асинхронного программирования и обработки данных. Каждое нововведение было направлено на решение конкретных проблем разработки и улучшение производительности программистов. Например, добавление LINQ существенно упростило работу с коллекциями данных, а внедрение async/await сделало асинхронное программирование более понятным и удобным.

Современные версии C# предоставляют разработчикам широкий набор инструментов для создания различных типов приложений: от простых консольных программ до сложных веб-приложений и систем машинного обучения. Язык активно поддерживает концепции функционального программирования, предоставляет мощные средства для работы с типами данных и включает встроенную поддержку параллельного программирования. В последних версиях особое внимание уделяется улучшению производительности и безопасности кода.

C# 1.0 - Основы языка



Первая версия языка C# была выпущена вместе с платформой .NET Framework 1.0 и представляла собой основополагающий набор возможностей для объектно-ориентированного программирования. Базовый синтаксис языка был разработан с учетом лучших практик существующих языков программирования, особенно Java и C++, но при этом предлагал ряд существенных улучшений и инноваций.

Система типов в C# 1.0 включала как примитивные типы данных (int, float, double, bool), так и ссылочные типы. Важной особенностью стала унифицированная система типов, в которой все типы, включая примитивные, наследуются от базового класса System.Object. Это позволило создать более согласованную модель программирования. Рассмотрим пример базового класса:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Customer
{
    private string name;
    private int age;
 
    public Customer(string name, int age)
    {
        this.name = name;
        this.age = age;
    }
 
    public string GetCustomerInfo()
    {
        return string.Format("Customer: {0}, Age: {1}", name, age);
    }
}
Управление памятью в C# 1.0 осуществляется с помощью автоматической сборки мусора, что значительно упрощает разработку по сравнению с языками с ручным управлением памятью. Платформа .NET автоматически отслеживает использование объектов и освобождает память, когда объекты становятся недоступными, что помогает избежать утечек памяти и других связанных проблем.

Обработка исключений реализована через механизм try-catch-finally, который позволяет создавать надежный код с правильной обработкой ошибок. Пример обработки исключений:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void ProcessFile(string path)
{
    FileStream file = null;
    try
    {
        file = File.OpenRead(path);
        // Обработка файла
    }
    catch (FileNotFoundException ex)
    {
        Console.WriteLine("File not found: " + ex.Message);
    }
    finally
    {
        if (file != null)
            file.Close();
    }
}
Делегаты стали важной частью первой версии C#, предоставляя механизм для реализации обработки событий и обратных вызовов. Они позволяют создавать более гибкие и расширяемые приложения. Пример использования делегата:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public delegate void MessageHandler(string message);
 
public class MessageProcessor
{
    private MessageHandler handler;
 
    public void RegisterHandler(MessageHandler newHandler)
    {
        handler = newHandler;
    }
 
    public void ProcessMessage(string message)
    {
        if (handler != null)
            handler(message);
    }
}
Свойства в C# 1.0 представили элегантный способ инкапсуляции полей класса, предоставляя публичный интерфейс для доступа к приватным данным. Это позволило создавать более чистый и поддерживаемый код. Механизм свойств стал одним из отличительных признаков языка, демонстрирующих его элегантность и практичность:

C#
1
2
3
4
5
6
7
8
9
public class Person
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}
В C# 1.0 также были представлены индексаторы, позволяющие работать с объектами как с массивами, и события, обеспечивающие стандартный механизм для реализации шаблона "наблюдатель". Эти возможности сделали язык особенно удобным для разработки приложений с графическим интерфейсом и компонентно-ориентированного программирования.

Интерфейсы в C# 1.0 предоставили мощный механизм для определения контрактов, которым должны следовать классы. Они позволяют определять набор методов и свойств, которые должны быть реализованы в классах, реализующих этот интерфейс. Это обеспечивает гибкость при проектировании системы и возможность создания взаимозаменяемых компонентов. Пример определения и использования интерфейса:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface ILogger
{
    void LogMessage(string message);
    void LogError(string error);
}
 
public class FileLogger : ILogger
{
    private string logPath;
 
    public FileLogger(string path)
    {
        logPath = path;
    }
 
    public void LogMessage(string message)
    {
        File.AppendAllText(logPath, "Message: " + message + Environment.NewLine);
    }
 
    public void LogError(string error)
    {
        File.AppendAllText(logPath, "Error: " + error + Environment.NewLine);
    }
}
Перегрузка операторов позволяет определять поведение стандартных операторов для пользовательских типов данных. Это делает код более интуитивно понятным и позволяет работать с пользовательскими типами так же естественно, как с встроенными типами данных. Рассмотрим пример класса, реализующего перегрузку операторов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public struct Complex
{
    private double real;
    private double imaginary;
 
    public Complex(double real, double imaginary)
    {
        this.real = real;
        this.imaginary = imaginary;
    }
 
    public static Complex operator +(Complex c1, Complex c2)
    {
        return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
    }
 
    public static Complex operator *(Complex c1, Complex c2)
    {
        return new Complex(
            c1.real * c2.real - c1.imaginary * c2.imaginary,
            c1.real * c2.imaginary + c1.imaginary * c2.real
        );
    }
}
Структуры в C# 1.0 представляют собой легковесные типы значений, которые могут содержать данные и методы. В отличие от классов, структуры хранятся в стеке, а не в куче, что делает их более эффективными для небольших объектов данных. Они особенно полезны при работе с примитивными типами данных и для создания неизменяемых объектов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public struct Point
{
    private int x;
    private int y;
 
    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
 
    public double DistanceTo(Point other)
    {
        int dx = x - other.x;
        int dy = y - other.y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
}
Пространства имен обеспечивают логическую организацию кода и предотвращают конфликты имен. Они позволяют группировать связанные классы, интерфейсы и другие типы в логические модули. Важной особенностью является возможность создавать вложенные пространства имен для более детальной организации кода:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace Company.Product.Module
{
    public class ServiceImplementation
    {
        private readonly ILogger logger;
 
        public ServiceImplementation(ILogger logger)
        {
            this.logger = logger;
        }
 
        public void ExecuteOperation()
        {
            try
            {
                // Выполнение операции
                logger.LogMessage("Operation completed successfully");
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
                throw;
            }
        }
    }
}
Атрибуты предоставляют механизм для добавления метаданных к элементам программы. Они могут быть использованы для различных целей, включая управление сериализацией, определение условий безопасности и настройку поведения компонентов во время выполнения. Атрибуты являются декларативным способом добавления дополнительной информации к коду:

C#
1
2
3
4
5
6
7
8
9
10
11
12
[Serializable]
public class Configuration
{
    [NonSerialized]
    private string temporaryData;
 
    [Obsolete("Use NewMethod instead")]
    public void OldMethod()
    {
        // Устаревшая реализация
    }
}

в чем отличия (нововведения) в WinForms 4.0
по сравнению со 2й версией

Нововведения C # 3.0. методы расширения
Задача А. Методы расширения (пример из лекции) Создать метод расширения для чисел типа double, который возвращает обратное число (1 / n). 1....

Как посмотреть нововведения C# 8 в Visual Studio?
Как посмотреть нововведения 8 шарпа в вижуал? Это, вроде, в превью, но как его активировать?

Как запустить локальную ms sql server 2016 версии на 2012 версии
Как запустить локальную ms sql server 2016 версии на 2012 версии Я в этом деле впервой, гуглил, но так и не смог сделать, может кто растолкует


C# 2.0 - 3.5 Расширение функциональности



Версии C# 2.0-3.5 принесли существенные улучшения в язык программирования, значительно расширив его возможности и сделав разработку более эффективной. Обобщенные типы (generics) стали одним из наиболее значимых нововведений C# 2.0, позволив создавать типобезопасный и переиспользуемый код. Они позволяют определять классы, интерфейсы и методы с параметрами типов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class GenericRepository<T> where T : class
{
    private readonly List<T> items = new List<T>();
 
    public void Add(T item)
    {
        items.Add(item);
    }
 
    public IEnumerable<T> Find(Predicate<T> predicate)
    {
        return items.FindAll(predicate);
    }
}
Частичные типы позволяют разделить определение класса или структуры на несколько файлов. Это особенно полезно при работе с автоматически генерируемым кодом, например, в Windows Forms или WPF. Каждая часть частичного типа может содержать различные члены класса:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public partial class Customer
{
    private string name;
    private int age;
 
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}
 
public partial class Customer
{
    public bool IsValid()
    {
        return !string.IsNullOrEmpty(name) && age >= 18;
    }
}
Анонимные методы представили новый способ определения делегатов inline, без необходимости создания отдельного именованного метода. Это сделало код более компактным и улучшило читаемость, особенно при работе с обработчиками событий:

C#
1
2
3
4
5
6
7
8
9
10
button.Click += delegate(object sender, EventArgs e)
{
    MessageBox.Show("Button clicked!");
};
 
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.FindAll(delegate(int number)
{
    return number % 2 == 0;
});
LINQ (Language Integrated Query), представленный в C# 3.0, произвел революцию в способе работы с данными. Он предоставил единый способ запроса данных из различных источников, включая коллекции в памяти, базы данных и XML. LINQ сочетает мощь SQL-подобного синтаксиса с безопасностью типов C#:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var customers = from c in context.Customers
                where c.Country == "Germany"
                orderby c.Name
                select new
                {
                    c.Name,
                    c.City,
                    OrderCount = c.Orders.Count()
                };
 
var numbers = Enumerable.Range(1, 100)
    .Where(n => n % 2 == 0)
    .Select(n => new { Number = n, Square = n * n })
    .Take(10);
Лямбда-выражения, введенные вместе с LINQ, предоставили еще более компактный способ определения анонимных функций. Они стали предпочтительным способом написания делегатов и поддерживают как выражения, так и блоки операторов:

C#
1
2
3
4
5
6
Func<int, bool> isEven = n => n % 2 == 0;
Action<string> log = message =>
{
    Console.WriteLine($"[{DateTime.Now}] {message}");
    File.AppendAllText("log.txt", message + Environment.NewLine);
};
Деревья выражений позволяют представлять код в виде структуры данных, которую можно анализировать и модифицировать во время выполнения. Это особенно полезно при работе с LINQ to SQL и Entity Framework, где выражения преобразуются в SQL-запросы:

C#
1
2
3
4
5
6
7
8
Expression<Func<Customer, bool>> predicate = c =>
    c.Age > 18 && c.Country == "USA";
 
var adult = customers.Where(predicate.Compile());
 
Expression<Func<int, int>> square = x => x * x;
var compiled = square.Compile();
int result = compiled(5); // результат: 25
Расширяющие методы позволяют добавлять новые методы к существующим типам без изменения их исходного кода. Это стало основой для создания многих удобных утилит и цепочек методов в LINQ:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static class StringExtensions
{
    public static int CountWords(this string str)
    {
        if (string.IsNullOrEmpty(str))
            return 0;
        return str.Split(new[] { ' ' }, 
            StringSplitOptions.RemoveEmptyEntries).Length;
    }
 
    public static string Truncate(this string str, int maxLength)
    {
        if (string.IsNullOrEmpty(str)) 
            return str;
        return str.Length <= maxLength 
            ? str 
            : str.Substring(0, maxLength) + "...";
    }
}
Автоматическая реализация свойств в C# 3.0 значительно упростила создание простых свойств, сократив количество шаблонного кода. Вместо явного определения закрытого поля и методов доступа разработчики получили возможность использовать более краткий синтаксис:

C#
1
2
3
4
5
6
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; private set; }
}
Анонимные типы предоставили возможность создавать объекты с набором свойств без явного определения класса. Это особенно полезно при проекции данных в LINQ-запросах и когда требуется временная структура данных:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var products = productList.Select(p => new
{
    ProductName = p.Name,
    CategoryName = p.Category.Name,
    Price = p.Price * 1.2m
}).ToList();
 
var reportData = orders.GroupBy(o => o.Customer)
    .Select(g => new
    {
        Customer = g.Key.Name,
        OrderCount = g.Count(),
        TotalAmount = g.Sum(o => o.Amount)
    });
Методы расширения для интерфейсов позволили добавлять новую функциональность к существующим интерфейсам. Это сделало возможным создание общих утилитарных методов, которые могут работать с любыми коллекциями, реализующими определенный интерфейс:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static class CollectionExtensions
{
    public static void AddRange<T>(this ICollection<T> collection, 
        IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
 
    public static IEnumerable<T> WhereNotNull<T>(
        this IEnumerable<T> source) where T : class
    {
        return source.Where(item => item != null);
    }
}
Инициализаторы объектов и коллекций предоставили более удобный способ создания и инициализации объектов и коллекций. Этот синтаксис позволяет установить значения свойств сразу после создания объекта:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var customer = new Customer
{
    Name = "John Doe",
    Age = 30,
    Address = new Address
    {
        Street = "123 Main St",
        City = "Springfield",
        Country = "USA"
    }
};
 
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var countries = new Dictionary<string, string>
{
    { "US", "United States" },
    { "UK", "United Kingdom" },
    { "FR", "France" }
};
Улучшенная поддержка делегатов включала возможность комбинировать делегаты с помощью операторов += и -=, что сделало работу с событиями более гибкой и удобной. Также появилась возможность создавать обобщенные делегаты:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class EventProcessor<T>
{
    public delegate void DataHandler<T>(T data);
    private DataHandler<T> handlers;
 
    public void RegisterHandler(DataHandler<T> handler)
    {
        handlers += handler;
    }
 
    public void UnregisterHandler(DataHandler<T> handler)
    {
        handlers -= handler;
    }
 
    public void ProcessData(T data)
    {
        handlers?.Invoke(data);
    }
}
Итераторы с использованием yield return сделали реализацию перечисляемых последовательностей более простой и эффективной. Этот механизм позволяет создавать последовательности элементов без необходимости хранить их все в памяти одновременно:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static class NumberGenerator
{
    public static IEnumerable<int> GenerateFibonacci(int count)
    {
        int current = 0, next = 1;
        for (int i = 0; i < count; i++)
        {
            yield return current;
            int temp = current + next;
            current = next;
            next = temp;
        }
    }
 
    public static IEnumerable<T> GeneratePages<T>(
        ICollection<T> items, int pageSize)
    {
        for (int i = 0; i < items.Count; i += pageSize)
        {
            yield return items.Skip(i).Take(pageSize);
        }
    }
}

C# 4.0 - 5.0 Асинхронность и динамика



Версии C# 4.0 и 5.0 представили революционные изменения в язык, сфокусировавшись на двух основных направлениях: динамическом программировании и асинхронных операциях. Динамическая типизация, введенная в C# 4.0, позволила более гибко работать с данными, типы которых неизвестны во время компиляции. Ключевое слово dynamic стало мощным инструментом для взаимодействия с динамическими языками и COM-объектами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class DynamicProcessor
{
    public void ProcessObject(dynamic obj)
    {
        try
        {
            obj.Execute();
            obj.SaveChanges();
            Console.WriteLine($"Result: {obj.Result}");
        }
        catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
        {
            Console.WriteLine($"Method not found: {ex.Message}");
        }
    }
}
Именованные и необязательные параметры значительно улучшили читаемость кода и сделали его более гибким. Эта функциональность особенно полезна при работе с методами, имеющими множество параметров:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ConfigurationManager
{
    public void Initialize(
        string connectionString,
        bool enableLogging = false,
        int timeout = 30,
        string logPath = null)
    {
        // Реализация инициализации
    }
}
 
public class Usage
{
    public void ConfigureSystem()
    {
        var config = new ConfigurationManager();
        config.Initialize(
            connectionString: "Server=.;Database=TestDB",
            enableLogging: true,
            logPath: @"C:\Logs\app.log"
        );
    }
}
Ковариантность и контравариантность в обобщенных интерфейсах и делегатах позволили создавать более гибкие и типобезопасные решения. Ключевые слова out и in используются для обозначения вариантности типов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
public interface IConverter<in TSource, out TTarget>
{
    TTarget Convert(TSource source);
}
 
public class NumberConverter : IConverter<int, object>
{
    public object Convert(int source)
    {
        return source.ToString();
    }
}
Асинхронное программирование получило значительное развитие в C# 5.0 с введением ключевых слов async и await. Эти нововведения сделали асинхронное программирование более понятным и удобным, позволяя писать асинхронный код, который выглядит почти как синхронный:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DataService
{
    private readonly HttpClient client = new HttpClient();
 
    public async Task<DataResult> ProcessDataAsync(string url)
    {
        try
        {
            var rawData = await client.GetStringAsync(url);
            var processedData = await ParseDataAsync(rawData);
            await SaveToDatabase(processedData);
            
            return new DataResult
            {
                Success = true,
                Data = processedData
            };
        }
        catch (Exception ex)
        {
            return new DataResult
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
}
Улучшенная поддержка параллелизма позволила эффективнее использовать многоядерные процессоры. Параллельное программирование стало проще с введением новых классов и методов в пространстве имен System.Threading.Tasks:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ParallelProcessor
{
    public async Task ProcessItemsAsync(IEnumerable<WorkItem> items)
    {
        var tasks = items.Select(async item =>
        {
            await Task.Delay(100); // Имитация асинхронной работы
            await ProcessSingleItemAsync(item);
        });
 
        await Task.WhenAll(tasks);
    }
 
    private async Task ProcessSingleItemAsync(WorkItem item)
    {
        try
        {
            var result = await Task.Run(() =>
            {
                // Тяжелые вычисления
                return item.Calculate();
            });
 
            await SaveResultAsync(result);
        }
        catch (Exception ex)
        {
            await LogErrorAsync(ex);
            throw;
        }
    }
}
Caller Information Attributes предоставили возможность получать информацию о вызывающем коде во время выполнения. Эти атрибуты особенно полезны при создании систем логирования и отладки:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Logger
{
    public void LogMessage(
        string message,
        [CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0)
    {
        var logEntry = new LogEntry
        {
            Message = message,
            MemberName = memberName,
            FilePath = sourceFilePath,
            LineNumber = sourceLineNumber,
            Timestamp = DateTime.UtcNow
        };
 
        WriteLogEntry(logEntry);
    }
}
Упрощенное взаимодействие с COM стало возможным благодаря улучшенной поддержке динамической типизации и необязательных параметров. Это сделало работу с COM-компонентами более естественной и менее подверженной ошибкам:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ExcelInterop
{
    public async Task GenerateReportAsync(ReportData data)
    {
        dynamic excel = Activator.CreateInstance(
            Type.GetTypeFromProgID("Excel.Application"));
        
        try
        {
            excel.Visible = true;
            dynamic workbook = excel.Workbooks.Add();
            dynamic sheet = workbook.ActiveSheet;
 
            await Task.Run(() =>
            {
                PopulateWorksheet(sheet, data);
                ApplyFormatting(sheet);
            });
 
            workbook.SaveAs("Report.xlsx");
        }
        finally
        {
            excel.Quit();
        }
    }
}
Улучшения в обработке исключений в асинхронном коде стали важной частью C# 5.0. Новый механизм позволяет сохранять контекст стека вызовов при возникновении исключений в асинхронных методах, что значительно упрощает отладку:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ExceptionHandler
{
    public async Task ProcessWithRetryAsync(Func<Task> operation)
    {
        int retryCount = 3;
        while (retryCount > 0)
        {
            try
            {
                await operation();
                break;
            }
            catch (Exception ex) when (retryCount > 1)
            {
                await Task.Delay(1000);
                retryCount--;
                await LogRetryAttemptAsync(ex, retryCount);
            }
        }
    }
 
    private async Task LogRetryAttemptAsync(Exception ex, int remainingAttempts)
    {
        await File.AppendAllTextAsync("error.log", 
            $"Error: {ex.Message}, Remaining attempts: {remainingAttempts}\n");
    }
}
Асинхронные потоки данных получили улучшенную поддержку через интеграцию с LINQ и другими компонентами платформы. Это позволило создавать более эффективные решения для обработки больших объемов данных:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class StreamProcessor
{
    private readonly Queue<byte[]> dataQueue = new Queue<byte[]>();
 
    public async Task ProcessLargeFileAsync(string filePath)
    {
        using var fileStream = File.OpenRead(filePath);
        using var reader = new StreamReader(fileStream);
 
        while (!reader.EndOfStream)
        {
            var buffer = new byte[4096];
            var bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);
            
            if (bytesRead > 0)
            {
                var data = new byte[bytesRead];
                Array.Copy(buffer, data, bytesRead);
                await ProcessDataChunkAsync(data);
            }
        }
    }
 
    private async Task ProcessDataChunkAsync(byte[] data)
    {
        await Task.Run(() =>
        {
            dataQueue.Enqueue(data);
            while (dataQueue.Count > 10)
            {
                var oldestChunk = dataQueue.Dequeue();
                ProcessChunk(oldestChunk);
            }
        });
    }
}
Интеграция с событиями в асинхронном контексте стала более естественной благодаря новым возможностям языка. Разработчики получили инструменты для создания асинхронных обработчиков событий и управления их жизненным циклом:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class EventHandling
{
    private readonly CancellationTokenSource cancellationSource = 
        new CancellationTokenSource();
 
    public async Task StartProcessingAsync()
    {
        try
        {
            await ProcessEventsAsync(cancellationSource.Token);
        }
        catch (OperationCanceledException)
        {
            await HandleCancellationAsync();
        }
    }
 
    private async Task ProcessEventsAsync(CancellationToken token)
    {
        var eventSource = new EventSource();
        eventSource.DataReceived += async (sender, e) =>
        {
            if (token.IsCancellationRequested)
                return;
 
            await ProcessEventDataAsync(e.Data);
        };
 
        await eventSource.StartAsync(token);
    }
}
Динамическая загрузка сборок и работа с рефлексией получили улучшенную поддержку благодаря интеграции с динамическими возможностями языка. Это позволило создавать более гибкие расширяемые приложения:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PluginLoader
{
    private readonly Dictionary<string, Assembly> loadedPlugins = 
        new Dictionary<string, Assembly>();
 
    public async Task<object> LoadAndCreateInstanceAsync(string assemblyPath)
    {
        var assembly = await Task.Run(() =>
            Assembly.LoadFile(assemblyPath));
 
        Type pluginType = assembly.GetTypes()
            .FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t));
 
        if (pluginType != null)
        {
            dynamic instance = Activator.CreateInstance(pluginType);
            await instance.InitializeAsync();
            return instance;
        }
 
        throw new InvalidOperationException("Valid plugin type not found");
    }
}
Улучшенная производительность асинхронных операций была достигнута благодаря оптимизациям в работе с Task и async/await. Новые возможности позволили создавать более эффективные асинхронные конвейеры обработки данных:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class PerformanceOptimization
{
    private readonly SemaphoreSlim semaphore = new SemaphoreSlim(5);
 
    public async Task ProcessItemsBatchAsync<T>(IEnumerable<T> items)
    {
        var tasks = new List<Task>();
        foreach (var item in items)
        {
            await semaphore.WaitAsync();
            tasks.Add(Task.Run(async () =>
            {
                try
                {
                    await ProcessSingleItemAsync(item);
                }
                finally
                {
                    semaphore.Release();
                }
            }));
        }
 
        await Task.WhenAll(tasks);
    }
 
    private async Task ProcessSingleItemAsync<T>(T item)
    {
        using var scope = new TransactionScope(
            TransactionScopeAsyncFlowOption.Enabled);
        
        await PerformOperationAsync(item);
        scope.Complete();
    }
}

C# 6.0 - 7.3 Синтаксический сахар



Версии C# 6.0-7.3 представили множество синтаксических улучшений, которые сделали код более лаконичным и выразительным. Интерполяция строк стала одним из самых заметных улучшений, позволяющим создавать форматированные строки более естественным способом. Вместо использования метода String.Format или конкатенации строк, разработчики получили возможность встраивать выражения непосредственно в строковые литералы:

C#
1
2
3
4
5
6
7
8
9
10
public class OrderProcessor
{
    public string GenerateOrderSummary(Order order)
    {
        return $"Order #{order.Id} - {order.Customer.Name}\n" +
               $"Total Items: {order.Items.Count}\n" +
               $"Total Amount: {order.TotalAmount:C2}\n" +
               $"Status: {order.Status}";
    }
}
Выражения членов в C# 6.0 позволили сократить синтаксис для методов и свойств, которые возвращают значение одним выражением. Это сделало код более компактным и читабельным:

C#
1
2
3
4
5
6
7
8
9
10
11
public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }
    public double Area => Width * Height;
    public double Perimeter => 2 * (Width + Height);
    public bool IsSquare => Width == Height;
    
    public string GetDescription() => 
        $"Rectangle: {Width}x{Height}, Area: {Area}";
}
Pattern matching стал мощным инструментом для работы с типами данных, позволяя более элегантно обрабатывать различные случаи и извлекать данные из объектов. Он включает сопоставление с типом, константами и свойствами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ShapeAnalyzer
{
    public double CalculateArea(object shape)
    {
        return shape switch
        {
            Rectangle r when r.Width == r.Height => r.Width * r.Width,
            Rectangle r => r.Width * r.Height,
            Circle c => Math.PI * c.Radius * c.Radius,
            Triangle t when t.IsRightAngled => 
                0.5 * t.Base * t.Height,
            _ => throw new ArgumentException("Unknown shape")
        };
    }
}
Локальные функции позволили определять методы внутри других методов, что особенно полезно для инкапсуляции вспомогательной логики, которая используется только в контексте конкретного метода:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class DataProcessor
{
    public async Task ProcessDataAsync(IEnumerable<DataItem> items)
    {
        async Task<ValidationResult> ValidateItemAsync(DataItem item)
        {
            await Task.Delay(100); // Имитация проверки
            return new ValidationResult
            {
                IsValid = item.Value > 0,
                ErrorMessage = item.Value <= 0 
                    ? "Value must be positive" 
                    : null
            };
        }
 
        foreach (var item in items)
        {
            var validationResult = await ValidateItemAsync(item);
            if (validationResult.IsValid)
            {
                await ProcessValidItemAsync(item);
            }
        }
    }
}
Кортежи и деконструкция упростили работу с множественными возвращаемыми значениями и их обработкой. Они предоставили типобезопасный способ группировки значений без необходимости создания специальных классов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class StatisticsCalculator
{
    public (double min, double max, double average) 
        CalculateStatistics(IEnumerable<double> values)
    {
        var sorted = values.OrderBy(v => v).ToList();
        return (
            min: sorted.First(),
            max: sorted.Last(),
            average: sorted.Average()
        );
    }
 
    public void ProcessStatistics(IEnumerable<double> data)
    {
        var (min, max, avg) = CalculateStatistics(data);
        var range = max - min;
        var deviation = data.Select(v => Math.Pow(v - avg, 2)).Average();
        
        Console.WriteLine($"Range: {range}, Deviation: {deviation}");
    }
}
Улучшения в работе с null включают оператор null-объединения и условный оператор null. Эти операторы сделали код более устойчивым к ошибкам, связанным с null-референсами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ConfigurationManager
{
    private readonly Dictionary<string, string> settings;
 
    public string GetSetting(string key, string defaultValue = null)
    {
        return settings?.GetValueOrDefault(key) ?? defaultValue;
    }
 
    public void UpdateSetting(string key, string value)
    {
        settings?[key] = value?.Trim();
        OnSettingChanged(key);
    }
}
Throw expressions позволили использовать оператор throw в выражениях, что сделало возможным более компактную проверку аргументов и обработку исключительных ситуаций:

C#
1
2
3
4
5
6
7
8
9
10
public class ValidationHelper
{
    public static T ValidateNotNull<T>(T value, string paramName) =>
        value ?? throw new ArgumentNullException(paramName);
 
    public static string ValidateString(string value) =>
        string.IsNullOrEmpty(value)
            ? throw new ArgumentException("Value cannot be empty")
            : value.Trim();
}
Ref returns и ref locals позволяют работать со ссылками на значения, а не только с самими значениями. Это особенно полезно при работе с большими структурами данных или когда требуется изменить элементы массива через вспомогательные методы:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ArrayHelper
{
    public static ref int FindLargestElement(int[] array)
    {
        ref int largest = ref array[0];
        for (int i = 1; i < array.Length; i++)
        {
            if (array[i] > largest)
            {
                largest = ref array[i];
            }
        }
        return ref largest;
    }
}
Улучшения в работе с литералами включают поддержку бинарных литералов и разделителей в числовых литералах. Это сделало код более читаемым при работе с битовыми операциями и большими числами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BitOperations
{
    private const int FLAG_A = 0b0001;
    private const int FLAG_B = 0b0010;
    private const int FLAG_C = 0b0100;
    private const long LARGE_NUMBER = 1_000_000_000_000;
 
    public int CombineFlags(bool useA, bool useB, bool useC)
    {
        return (useA ? FLAG_A : 0) |
               (useB ? FLAG_B : 0) |
               (useC ? FLAG_C : 0);
    }
}
Улучшения в работе с выражениями включают поддержку out-переменных в выражениях и возможность использования выражений в инициализаторах. Это позволило создавать более компактный и выразительный код:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ParsingHelper
{
    public bool TryGetValue(string input, out double result)
    {
        if (double.TryParse(input, out var parsed))
        {
            result = Math.Round(parsed, 2);
            return true;
        }
        result = default;
        return false;
    }
}
Деконструкция в циклах foreach позволила более элегантно работать с коллекциями пар или кортежей. Это особенно полезно при обработке словарей или наборов данных с множественными значениями:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DataProcessor
{
    public void ProcessKeyValuePairs(Dictionary<string, int> data)
    {
        foreach (var (key, value) in data)
        {
            if (value > 100)
            {
                ProcessHighValueItem(key, value);
            }
        }
    }
 
    public void ProcessCoordinates(List<(int x, int y)> points)
    {
        foreach (var (x, y) in points)
        {
            var distance = Math.Sqrt(x * x + y * y);
            ProcessPoint(x, y, distance);
        }
    }
}
Улучшения в работе с делегатами включают более компактный синтаксис для определения и использования методов в качестве делегатов. Это сделало код более читаемым при работе с событиями и обратными вызовами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public class EventManager
{
    private event Action<string> OnMessageReceived;
 
    public void Subscribe(Action<string> handler) => 
        OnMessageReceived += handler;
 
    public void Unsubscribe(Action<string> handler) => 
        OnMessageReceived -= handler;
 
    public void ProcessMessage(string message) => 
        OnMessageReceived?.Invoke(message);
}
Улучшения в синтаксисе свойств позволили создавать более компактные определения свойств с автоматической реализацией и инициализацией. Это особенно полезно при работе с моделями данных и конфигурационными классами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserProfile
{
    private readonly ILogger logger;
    public string Username { get; private set; } = "Guest";
    public DateTime LastLogin { get; } = DateTime.UtcNow;
    public List<string> Permissions { get; } = new List<string>();
    
    public string FullName
    {
        get => $"{FirstName} {LastName}";
        set
        {
            var parts = value.Split(' ');
            FirstName = parts.FirstOrDefault() ?? "";
            LastName = parts.Length > 1 ? parts[1] : "";
        }
    }
}

C# 8.0 - 11.0 Современные возможности



Современные версии C# привнесли множество инновационных возможностей, значительно расширяющих функциональность языка. Nullable reference types стали одним из наиболее важных нововведений C# 8.0, позволяющим предотвращать ошибки, связанные с null-референсами на этапе компиляции:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CustomerService
{
    public Customer? FindCustomer(string? id)
    {
        if (string.IsNullOrEmpty(id))
            return null;
 
        return _repository.GetById(id);
    }
 
    public void ProcessCustomer(Customer customer)
    {
        // Компилятор предупредит, если customer может быть null
        Console.WriteLine(customer.Name);
    }
}
Records представляют собой новый тип ссылочных типов, предназначенный для создания неизменяемых объектов данных. Они особенно полезны при работе с данными, которые должны быть неизменными:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public record Person(string FirstName, string LastName, DateTime DateOfBirth)
{
    public string FullName => $"{FirstName} {LastName}";
    public int Age => DateTime.Now.Year - DateOfBirth.Year;
}
 
public record Employee : Person
{
    public Employee(string firstName, string lastName, DateTime dateOfBirth, 
        decimal salary) 
        : base(firstName, lastName, dateOfBirth)
    {
        Salary = salary;
    }
 
    public decimal Salary { get; init; }
}
Pattern matching получил существенные улучшения в последних версиях C#, включая поддержку сопоставления с типами и свойствами в более сложных сценариях:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public class DocumentProcessor
{
    public string AnalyzeDocument(Document doc) => doc switch
    {
        Invoice { Total: > 1000 } invoice => 
            $"High-value invoice: {invoice.Total}",
        Contract { IsExpired: true } contract => 
            $"Expired contract from {contract.StartDate}",
        Report { Pages: > 100 } report => 
            $"Long report with {report.Pages} pages",
        _ => "Unknown document type"
    };
}
Init-only свойства предоставляют механизм для создания неизменяемых свойств, которые могут быть установлены только при инициализации объекта:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Configuration
{
    public string DatabaseConnection { get; init; }
    public int MaxConnections { get; init; }
    public TimeSpan Timeout { get; init; }
 
    public Configuration WithTimeout(TimeSpan newTimeout) =>
        new Configuration
        {
            DatabaseConnection = this.DatabaseConnection,
            MaxConnections = this.MaxConnections,
            Timeout = newTimeout
        };
}
Top-level statements позволяют писать программы без явного определения класса и метода Main, что особенно удобно для небольших утилит и скриптов:

C#
1
2
3
4
5
6
7
using System.Net.Http;
 
var client = new HttpClient();
var response = await client.GetStringAsync("https://api.example.com/data");
Console.WriteLine(response);
 
await File.WriteAllTextAsync("response.txt", response);
Улучшенные интерфейсы в C# 8.0 получили возможность включать реализации методов по умолчанию, что позволяет добавлять новые методы в интерфейсы без нарушения обратной совместимости:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ILogger
{
    void Log(string message);
    void LogError(string error) => Log($"ERROR: {error}");
    void LogWarning(string warning) => Log($"WARNING: {warning}");
}
 
public class FileLogger : ILogger
{
    public void Log(string message)
    {
        File.AppendAllText("log.txt", 
            $"{DateTime.Now}: {message}\n");
    }
}
Target-typed new expressions упрощают создание объектов, когда тип может быть выведен из контекста:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DataService
{
    private readonly HttpClient client = new();
    private readonly Dictionary<string, int> cache = new();
    
    public async Task<List<string>> GetDataAsync()
    {
        var items = new List<string>();
        var response = await client.GetAsync("api/data");
        if (response.IsSuccessStatusCode)
        {
            items.AddRange(await response.Content
                .ReadFromJsonAsync<List<string>>());
        }
        return items;
    }
}
Улучшенная поддержка функционального программирования включает новые возможности для работы с неизменяемыми данными и функциональными концепциями:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class FunctionalExtensions
{
    public static Option<T> ToOption<T>(this T? value) 
        where T : class =>
        value is not null ? new Some<T>(value) : None<T>.Instance;
 
    public static Option<TResult> Bind<T, TResult>(
        this Option<T> option,
        Func<T, Option<TResult>> func) =>
        option.Match(
            some: value => func(value),
            none: () => None<TResult>.Instance
        );
}
Source generators стали мощным инструментом для автоматической генерации кода во время компиляции. Они позволяют создавать дополнительные файлы исходного кода, которые включаются в процесс компиляции:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[Generator]
public class DtoGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        foreach (var syntaxTree in context.Compilation.SyntaxTrees)
        {
            var classNodes = syntaxTree
                .GetRoot()
                .DescendantNodes()
                .OfType<ClassDeclarationSyntax>();
 
            foreach (var classNode in classNodes)
            {
                GenerateDtoClass(classNode, context);
            }
        }
    }
}
Модули файлов позволяют группировать связанные типы в одном файле, сохраняя при этом их изоляцию. Это особенно полезно при работе с небольшими вспомогательными типами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module Numbers
{
    public struct Complex
    {
        public double Real { get; init; }
        public double Imaginary { get; init; }
    }
 
    public static class ComplexMath
    {
        public static Complex Add(Complex a, Complex b) =>
            new() { 
                Real = a.Real + b.Real, 
                Imaginary = a.Imaginary + b.Imaginary 
            };
    }
}
Улучшения в обработке строк включают интерполированные строки с форматированием и новые методы для работы со строками:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StringProcessor
{
    public string FormatDocument(Document doc)
    {
        const string template = """
            Document ID: {id}
            Title: {title}
            Created: {date:yyyy-MM-dd}
            Status: {status}
            """;
 
        return template.Replace("{id}", doc.Id.ToString())
            .Replace("{title}", doc.Title)
            .Replace("{date}", doc.CreatedDate.ToString("yyyy-MM-dd"))
            .Replace("{status}", doc.Status.ToString());
    }
}
Коварианция возвращаемых типов позволяет переопределенным методам возвращать более конкретные типы, чем определено в базовом классе:

C#
1
2
3
4
5
6
7
8
9
public class AnimalFactory
{
    public virtual Animal CreateAnimal() => new Animal();
}
 
public class DogFactory : AnimalFactory
{
    public override Dog CreateAnimal() => new Dog();
}
Расширенная поддержка параллелизма включает новые возможности для работы с асинхронными операциями и параллельной обработкой данных:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ParallelProcessor
{
    private readonly Channel<WorkItem> workItems = 
        Channel.CreateUnbounded<WorkItem>();
 
    public async Task ProcessItemsAsync(
        IAsyncEnumerable<WorkItem> items, 
        CancellationToken token)
    {
        await foreach (var item in items.WithCancellation(token))
        {
            await workItems.Writer.WriteAsync(item, token);
        }
 
        await Task.WhenAll(Enumerable.Range(0, Environment.ProcessorCount)
            .Select(_ => ProcessWorkerAsync(token)));
    }
 
    private async Task ProcessWorkerAsync(CancellationToken token)
    {
        await foreach (var item in workItems.Reader.ReadAllAsync(token))
        {
            await ProcessSingleItemAsync(item);
        }
    }
}
Улучшения в работе с типами значений включают новые возможности для создания эффективных структур данных и оптимизации производительности:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public readonly struct Point3D
{
    public readonly double X { get; init; }
    public readonly double Y { get; init; }
    public readonly double Z { get; init; }
 
    public double DistanceTo(Point3D other)
    {
        var dx = X - other.X;
        var dy = Y - other.Y;
        var dz = Z - other.Z;
        return Math.Sqrt(dx * dx + dy * dy + dz * dz);
    }
}
Range и Index предоставляют новый синтаксис для работы с диапазонами в массивах и коллекциях:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ArrayOperations
{
    public T[] GetRange<T>(T[] array, Range range)
    {
        var (start, length) = range.GetOffsetAndLength(array.Length);
        var result = new T[length];
        Array.Copy(array, start, result, 0, length);
        return result;
    }
 
    public T[] GetLastElements<T>(T[] array, Index count)
    {
        return array[^count..];
    }
}

Эволюция паттернов в C#



Паттерны проектирования в C# претерпели значительную эволюцию с момента появления языка, адаптируясь к новым возможностям и современным подходам к разработке программного обеспечения. Традиционные паттерны проектирования получили новые реализации благодаря развитию языковых возможностей C#. Рассмотрим, как изменились популярные паттерны с учетом современных возможностей языка.

Паттерн Singleton в современном C# может быть реализован более эффективно и безопасно благодаря статическим конструкторам и свойствам только для чтения:

C#
1
2
3
4
5
6
7
8
9
10
11
12
public sealed class Singleton
{
    private static readonly Lazy<Singleton> instance = 
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Instance => instance.Value;
    
    private Singleton()
    {
        // Инициализация
    }
}
Паттерн Factory Method эволюционировал благодаря обобщенным типам и ковариантности возвращаемых типов. Современная реализация может выглядеть следующим образом:

C#
1
2
3
4
5
6
7
8
9
public interface IFactory<out T> where T : class
{
    T Create();
}
 
public class ProductFactory<T> : IFactory<T> where T : class, new()
{
    public T Create() => new T();
}
Паттерн Observer получил новую жизнь с появлением событий и делегатов в C#, а затем эволюционировал с появлением реактивного программирования:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ModernObservable<T>
{
    private readonly List<IObserver<T>> observers = new();
    
    public IDisposable Subscribe(IObserver<T> observer)
    {
        observers.Add(observer);
        return new Unsubscriber(() => observers.Remove(observer));
    }
    
    protected void NotifyObservers(T value)
    {
        foreach (var observer in observers.ToList())
        {
            observer.OnNext(value);
        }
    }
}
Паттерн Strategy стал более гибким благодаря делегатам и лямбда-выражениям. Теперь стратегии могут быть определены как простые функции:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DataProcessor
{
    private readonly Func<string, string> processStrategy;
    
    public DataProcessor(Func<string, string> strategy)
    {
        processStrategy = strategy;
    }
    
    public string ProcessData(string input) => processStrategy(input);
}
 
// Использование
var processor = new DataProcessor(input => input.ToUpper());
Паттерн Decorator получил новую реализацию с использованием интерфейсов с реализацией по умолчанию и записей:

C#
1
2
3
4
5
6
7
8
9
10
public interface IComponent
{
    string Operation() => "Base Operation";
}
 
public record Decorator(IComponent Component) : IComponent
{
    public virtual string Operation() =>
        $"Decorator({Component.Operation()})";
}
Паттерн Builder эволюционировал с появлением инициализаторов объектов и методов расширения:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PersonBuilder
{
    private readonly Person person = new();
    
    public PersonBuilder WithName(string name)
    {
        person.Name = name;
        return this;
    }
    
    public PersonBuilder WithAge(int age)
    {
        person.Age = age;
        return this;
    }
    
    public Person Build() => person;
}
Паттерн Command стал более компактным благодаря делегатам и замыканиям:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CommandManager
{
    private readonly Dictionary<string, Func<Task>> commands = new();
    
    public void RegisterCommand(string name, Func<Task> command)
    {
        commands[name] = command;
    }
    
    public async Task ExecuteCommand(string name)
    {
        if (commands.TryGetValue(name, out var command))
        {
            await command();
        }
    }
}
Паттерн Chain of Responsibility получил новую реализацию с использованием async/await и LINQ:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class RequestProcessor
{
    private readonly IEnumerable<Func<Request, Task<bool>>> handlers;
    
    public RequestProcessor(IEnumerable<Func<Request, Task<bool>>> handlers)
    {
        this.handlers = handlers;
    }
    
    public async Task ProcessRequest(Request request)
    {
        foreach (var handler in handlers)
        {
            if (await handler(request))
                break;
        }
    }
}
Паттерн State получил элегантную реализацию с использованием switch expressions и паттернов сопоставления:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract record OrderState
{
    public virtual OrderState ProcessOrder() => this;
}
 
public record NewOrderState : OrderState
{
    public override OrderState ProcessOrder() =>
        new ProcessingOrderState();
}
 
public class Order
{
    private OrderState state = new NewOrderState();
    
    public void Process()
    {
        state = state switch
        {
            NewOrderState => new ProcessingOrderState(),
            ProcessingOrderState => new CompletedOrderState(),
            _ => state
        };
    }
}
Паттерн Template Method эволюционировал с появлением виртуальных методов расширения и абстрактных классов с реализацией по умолчанию:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class DataExporter
{
    public async Task ExportAsync<T>(IEnumerable<T> data)
    {
        await PrepareExportAsync();
        foreach (var item in data)
        {
            await ExportItemAsync(item);
        }
        await FinalizeExportAsync();
    }
    
    protected virtual Task PrepareExportAsync() => Task.CompletedTask;
    protected abstract Task ExportItemAsync<T>(T item);
    protected virtual Task FinalizeExportAsync() => Task.CompletedTask;
}
Паттерн Proxy был адаптирован для работы с асинхронными операциями и динамическими типами:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AsyncProxy<T> where T : class
{
    private readonly Lazy<Task<T>> target;
    
    public AsyncProxy(Func<Task<T>> factory)
    {
        target = new Lazy<Task<T>>(factory);
    }
    
    public async Task<TResult> InvokeAsync<TResult>(
        Func<T, Task<TResult>> operation)
    {
        var instance = await target.Value;
        return await operation(instance);
    }
}
Паттерн Composite получил новую реализацию с использованием рекурсивных паттернов и записей:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract record Component
{
    public abstract decimal Calculate();
}
 
public record Leaf(decimal Value) : Component
{
    public override decimal Calculate() => Value;
}
 
public record Composite(IReadOnlyList<Component> Children) : Component
{
    public override decimal Calculate() =>
        Children.Sum(child => child.Calculate());
}
Паттерн Visitor был модернизирован с использованием паттернов сопоставления и обобщенных типов:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IVisitor<T>
{
    T Visit(IElement element);
}
 
public class ModernVisitor<T> : IVisitor<T>
{
    public T Visit(IElement element) => element switch
    {
        ConcreteElementA a => VisitElementA(a),
        ConcreteElementB b => VisitElementB(b),
        _ => throw new ArgumentException("Unknown element type")
    };
    
    protected virtual T VisitElementA(ConcreteElementA element) =>
        default!;
    
    protected virtual T VisitElementB(ConcreteElementB element) =>
        default!;
}
Паттерн Mediator эволюционировал в контексте асинхронного программирования и обработки событий:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ModernMediator
{
    private readonly Dictionary<Type, Func<object, Task>> handlers = new();
    
    public void Register<T>(Func<T, Task> handler)
    {
        handlers[typeof(T)] = message => 
            handler((T)message);
    }
    
    public async Task SendAsync<T>(T message)
    {
        if (handlers.TryGetValue(typeof(T), out var handler))
        {
            await handler(message);
        }
    }
}
Паттерн Specification был адаптирован для работы с лямбда-выражениями и LINQ:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Specification<T>
{
    private readonly Expression<Func<T, bool>> expression;
    
    public Specification(Expression<Func<T, bool>> expression)
    {
        this.expression = expression;
    }
    
    public bool IsSatisfiedBy(T entity)
    {
        return expression.Compile()(entity);
    }
    
    public Specification<T> And(Specification<T> other)
    {
        var parameter = Expression.Parameter(typeof(T));
        var body = Expression.AndAlso(
            expression.Body,
            other.expression.Body
        );
        return new Specification<T>(
            Expression.Lambda<Func<T, bool>>(body, parameter)
        );
    }
}
Паттерн Unit of Work был модернизирован с учетом современных возможностей управления транзакциями и асинхронных операций:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class UnitOfWork : IAsyncDisposable
{
    private readonly DbContext context;
    private readonly Dictionary<Type, object> repositories = new();
    
    public IRepository<T> GetRepository<T>() where T : class
    {
        var type = typeof(T);
        if (!repositories.ContainsKey(type))
        {
            repositories[type] = new Repository<T>(context);
        }
        return (IRepository<T>)repositories[type];
    }
    
    public async Task<int> SaveChangesAsync()
    {
        using var transaction = await context.Database
            .BeginTransactionAsync();
        try
        {
            var result = await context.SaveChangesAsync();
            await transaction.CommitAsync();
            return result;
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
    
    public async ValueTask DisposeAsync()
    {
        await context.DisposeAsync();
    }
}

Итоги развития языка C#



Развитие языка программирования C# демонстрирует последовательное движение в сторону повышения продуктивности разработчиков при сохранении высокой производительности и надежности кода. Эволюция языка от первой версии до современных реализаций показывает, как C# адаптируется к меняющимся потребностям разработки программного обеспечения, сохраняя при этом свои основные принципы и философию.

Каждая версия языка C# привносила значительные улучшения, которые делали разработку более эффективной и удобной. От базовых конструкций объектно-ориентированного программирования в C# 1.0 до современных возможностей функционального программирования и обработки данных, язык последовательно развивался, обеспечивая разработчиков все более мощными инструментами.

Важной особенностью развития C# является сохранение обратной совместимости при добавлении новых возможностей. Это означает, что код, написанный на ранних версиях языка, продолжает работать в более новых версиях, что критически важно для поддержки существующих проектов и постепенного перехода на новые возможности языка.

Современный C# представляет собой зрелый язык программирования, который успешно сочетает объектно-ориентированный, функциональный и императивный стили программирования. Поддержка асинхронного программирования, паттернов сопоставления, null-безопасности и других современных концепций делает его одним из наиболее универсальных и мощных языков программирования.

Будущее развитие C# продолжает фокусироваться на улучшении продуктивности разработчиков, безопасности кода и производительности. Язык активно развивается в направлении упрощения сложных концепций программирования, делая их более доступными для разработчиков всех уровней, при этом сохраняя мощь и гибкость, необходимые для создания современных приложений.

Нововведения в Firebase Storage 16й версии
Доброго времени уважаемые форумчане, столкнулся я с такой проблемой был у меня проект на Firebase Storage 11й версии, потом я его заморозил и вот...

В чем отличия версии
В чем отличия visual prolog 5.2 от Turbo Prolog? У них сильно разный синтаксис? Можете кинуть ссылки на его описание(синтаксис)?

Здравстуйте! В чем отличия УТ 8.3 и 8.2 версии 10.2 ?
В чем изменения? мне нужно было поставить 8.2 , а программисты поставили 8.3 ... Добавлено через 1 минуту Тьфу, то есть версии 10.3 извиняюсь

Версии Asterisk Отличия/какие использовать?
Товарищи доброго времени суток! Пытаюсь понять, в чем смысл в версиях Астера? С одной стороны понятно, сделали версию Астера, далее что то...

В чем отличия демонстрационной версии FastReport?
Здравствуйте! поясните, пожалуйста, по программке, на оф сайте ничего не нашел поэтому поводу... Программа вроде как платная, н я вроде скачал и...

Отличия 7 и 8 версии true dbgrid & dblist
Расскажите, чем принципиально отличается сабж версия 7 от 8? Если у кого есть сериалы к 8, киньте в мыло плз. Спасибо.

Нововведения qt
Какие существенные нововведения привносит Qt в разработку ?

Нововведения
Вроде такой темы еще не было: У меня на 1280*800 теперь видно 3 спецразмещения и первые 3 результата поиска

Нововведения в Яндекс
В яндексе появилось множество нововведений, интерфейс стал веб2.0. Некоторые из новшеств: удобный выбор региона в футере, отправка отзыва о...

Нововведения и трафик
Собственно хочется выяснить, как последние нововведеия Яндекса отражаются на траф. Статистика LI не дает возможности это выяснить, т.к. пользователи...

Нововведения в RAD Studio 10
Выпустили, странно 9-ки нет (и о ней ни слова не нашел у них на сайте, может как с windows 10). Из видео презентации стало понятно, что ввели...

10036 сборка! Нововведения!
Кто как оценил нововведения 10036 сборки? Мне кажется её теперь как основную ОС ставить можно, багов стало очень мало (я не нашёл ни 1 пока-что), и...

Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Laravel 11: новые возможности, гайд по обновлению
Wired 18.02.2025
Laravel 11 - это новая масштабная версия одного из самых популярных PHP-фреймворков, выпущенная в марте 2024 года. Эта версия продолжает традицию внедрения передовых технологий и методологий. . .
Миграции в Laravel
Wired 18.02.2025
Разработка веб-приложений на Laravel неразрывно связана с управлением структурой базы данных. При работе над проектом часто возникает необходимость вносить изменения в схему базы данных - добавлять. . .
Аутентификация в Laravel
Wired 18.02.2025
В современном мире веб-разработки безопасность пользовательских данных становится критически важным аспектом любого приложения. Laravel, как один из самых популярных PHP-фреймворков, предоставляет. . .
Laravel или Symfony: что лучше для старта?
Wired 18.02.2025
В веб-разработке выбор правильного фреймворка может стать определяющим фактором успеха проекта. Особенно это актуально для PHP - одного из самых распространенных языков программирования, где Laravel. . .
Что нового в Laravel 12
Wired 18.02.2025
С момента своего появления в 2011 году Laravel постоянно развивается, внедряя инновационные решения и совершенствуя существующие возможности. В начале 2025 года ожидается выход Laravel 12 - новой. . .
Роутер в Laravel: как работать с маршрутами
Wired 18.02.2025
Маршрутизация - один из основополагающих элементов любого веб-приложения на Laravel, определяющий как приложение отвечает на HTTP-запросы к различным URL-адресам. По сути, роутинг - это механизм. . .
Интеграция шаблона Bootstrap в Laravel PHP
Wired 18.02.2025
Разработка веб-приложений в современном мире требует не только надежного бэкенда, но и привлекательного, отзывчивого интерфейса. Laravel, как один из самых популярных PHP-фреймворков, отлично. . .
Использование контроллеров и middleware в Laravel PHP
Wired 18.02.2025
Современная веб-разработка требует четкой организации кода и эффективного управления потоком HTTP-запросов. Laravel, как один из ведущих PHP-фреймворков, предоставляет два мощных инструмента для. . .
Фильтрация массива по неточному соответствию элементам другого массива в JavaScript
Wired 18.02.2025
При работе с массивами данных в JavaScript иногда возникает задача поиска и фильтрации элементов по неточному соответствию. В отличие от точного сравнения, когда мы ищем полное совпадение значений,. . .
Создаем SPA Router на чистом JavaScript
bytestream 17.02.2025
В современной веб-разработке одностраничные приложения (SPA) стали стандартом для создания динамичных и отзывчивых пользовательских интерфейсов. Ключевым компонентом любого SPA является роутер -. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru