C Sharp

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
С#
Изображение логотипа
Класс языка
Появился в 2001
Автор Андерс Хейлсберг
Разработчик .NET Foundation
Расширение файлов .cs или .csx
Выпуск 13 (14 ноября 2024 года)
Система типов статическая, динамическая, строгая, безопасная, вывод типов
Основные реализации .NET Framework, Mono, .NET, DotGNU (заморожен), Universal Windows Platform
Диалекты , Spec#, Polyphonic C#[англ.], Enhanced C#
Испытал влияние C++, Java[1][2][3], Delphi, Модула-3 и Smalltalk
Повлиял на , F#, Nemerle, Vala, Windows PowerShell, Kotlin
Лицензия

Компилятор Roslyn: лицензия MIT[4]
.NET Core CLR: лицензия MIT[5]

Компилятор Mono: dual GPLv3 and MIT/X11

DotGNU: dual GPL and LGPL
Сайт docs.microsoft.com/ru-ru…
Платформа Common Language Infrastructure
Логотип Викисклада Медиафайлы на Викискладе

C# (произносится си шарп) — объектно-ориентированный язык программирования общего назначения. Разработан в 19982001 годах группой инженеров компании Microsoft под руководством Андерса Хейлсберга и Скотта Вильтаумота[6] как язык разработки приложений для платформы Microsoft .NET Framework и .NET Core. Впоследствии был стандартизирован как ECMA-334 и ISO/IEC 23270.

C# относится к семье языков с C-подобным синтаксисом, из них его синтаксис наиболее близок к C++ и Java. Язык имеет статическую типизацию, поддерживает полиморфизм, перегрузку операторов (в том числе операторов явного и неявного приведения типа), делегаты, атрибуты, события, переменные, свойства, обобщённые типы и методы, итераторы, анонимные функции с поддержкой замыканий, LINQ, исключения, комментарии в формате XML.

Переняв многое от своих предшественников — языков C++, Delphi, Модула, Smalltalk и, в особенности, Java — С#, опираясь на практику их использования, исключает некоторые модели, зарекомендовавшие себя как проблематичные при разработке программных систем, например, C# в отличие от C++ не поддерживает множественное наследование классов (между тем допускается множественная реализация интерфейсов).

Особенности языка

[править | править код]

С# разрабатывался как язык программирования прикладного уровня для CLR и, как таковой, зависит, прежде всего, от возможностей самой CLR. Это касается, прежде всего, системы типов С#, которая отражает BCL. Присутствие или отсутствие тех или иных выразительных особенностей языка диктуется тем, может ли конкретная языковая особенность быть транслирована в соответствующие конструкции CLR. Так, с развитием CLR от версии 1.1 к 2.0 значительно обогатился и сам C#; подобного взаимодействия следует ожидать и в дальнейшем (однако, эта закономерность была нарушена с выходом C# 3.0, представляющего собой расширения языка, не опирающиеся на расширения платформы .NET). CLR предоставляет С#, как и всем другим .NET-ориентированным языкам, многие возможности, которых лишены «классические» языки программирования. Например, сборка мусора не реализована в самом C#, а производится CLR для программ, написанных на C#, точно так же, как это делается для программ на VB.NET, J# и др.

Название языка

[править | править код]
Нота C♯[англ.]

Название «Си шарп» (от англ. sharp — диез) происходит от буквенной музыкальной нотации, где латинской букве C соответствует нота До, а знак диез (англ. sharp) означает повышение соответствующего ноте звука на полутон[7], что аналогично названию языка C++, где «++» обозначает инкремент переменной. Название также является игрой с цепочкой CC++ → C++++(C#), так как символ «#» можно представить состоящим из 4 знаков «+»[8].

Из-за технических ограничений на отображение (стандартные шрифты, браузеры и т. д.), а также из-за того, что знак диеза ♯ не представлен на стандартной клавиатуре компьютера, при записи имени языка программирования используют знак решётки (#)[9]. Это соглашение отражено в Спецификации языка C# ECMA-334[10]. Тем не менее, на практике (например, при размещении рекламы и коробочном дизайне[11]), «Майкрософт» использует знак диеза.

Названия языков программирования не принято переводить, поэтому язык называют, используя транскрипцию, — «Си шарп».

Стандартизация

[править | править код]

C# стандартизирован в ECMA (ECMA-334)[12] и ISO (ISO/IEC 23270)[13].

Известно как минимум о трёх независимых реализациях C#, базирующихся на этой спецификации и находящихся в настоящее время на различных стадиях разработки:

На протяжении разработки языка C# было выпущено несколько его версий:

Версия Спецификация языка Дата выхода Совместимые версии .NET Совместимая версия Visual Studio
ECMA ISO/IEC Microsoft
C# 1.0 Декабрь 2002 Апрель 2003 (недоступная ссылка) Январь 2002 Январь 2002 .NET Framework 1.0 Visual Studio .NET (2002)
C# 1.1
C# 1.2
Октябрь 2003 Апрель 2003 .NET Framework 1.1 Visual Studio .NET 2003
C# 2.0 Июнь 2006 Сентябрь 2006 Сентябрь 2005[14] Ноябрь 2005 .NET Framework 2.0
.NET Framework 3.0
Visual Studio 2005
C# 3.0 Отсутствует[15] Август 2007 Ноябрь 2007 .NET Framework 2.0 (кроме LINQ)
.NET Framework 3.0 (кроме LINQ)
.NET Framework 3.5
Visual Studio 2008
C# 4.0 Апрель 2010 Апрель 2010 .NET Framework 4.0 Visual Studio 2010
C# 5.0 Декабрь 2017 Декабрь 2018 Июнь 2013 Август 2012 .NET Framework 4.5 Visual Studio 2012
C# 6.0 Июнь 2022 Отсутствует Июль 2015 .NET Framework 4.6
.NET Core 1.0
.NET Core 1.1
Visual Studio 2015
C# 7.0 Декабрь 2023 Сентябрь 2023 Март 2017 .NET Framework 4.6.2
.NET Framework 4.7
Visual Studio 2017 15.0
C# 7.1 Отсутствует Август 2017 .NET Core 2.0 Visual Studio 2017 15.3
C# 7.2 Ноябрь 2017 Visual Studio 2017 15.5
C# 7.3 Май 2018 .NET Core 2.1
.NET Core 2.2
.NET Framework 4.8
Visual Studio 2017 15.7
C# 8.0 Сентябрь 2019 .NET Core 3.0
.NET Core 3.1
.NET Framework 4.8
Visual Studio 2019 16.3
C# 9.0 Сентябрь 2020 .NET 5.0 Visual Studio 2019 16.8
C# 10.0 Июль 2021 .NET 6.0 Visual Studio 2022 17.0
C# 11.0 Ноябрь 2022 .NET 7.0 Visual Studio 2022 17.4
C# 12.0 Ноябрь 2023 .NET 8.0 Visual Studio 2022 17.8[16]
Общая информация по версиям
Версия Нововведения
C# 2.0
  • Частичные типы
  • Обобщённые типы (generics)
  • Итераторы и ключевое слово yield
  • Анонимные методы
  • Оператор null-объединения
  • Nullable-типы
C# 3.0
  • Запросы, интегрированные в язык (LINQ)
  • Инициализаторы объектов и коллекций
  • Лямбда-выражения
  • Деревья выражений
  • Неявная типизация и ключевое слово var
  • Анонимные типы
  • Методы расширения
  • Автоматические свойства
C# 4.0
  • Динамическое связывание и ключевое слово dynamic
  • Именованные и опциональные аргументы
  • Обобщенная ковариантность и контрвариантность
  • Библиотека TPL, концепция задач и классы Task, Parallel
  • Класс MemoryCache
  • Классы параллельных коллекций
C# 5.0
  • Шаблон TAP
  • Асинхронные методы async и await
  • Сведения о вызывающем объекте
C# 6.0
  • Компилятор как сервис
  • Импорт членов статических типов в пространство имён
  • Фильтры исключений
  • await в блоках catch/finally
  • Инициализаторы автосвойств
  • Автосвойства только для чтения
  • null-условные операции (?. и ?[])
  • Интерполяция строк
  • Оператор nameof
  • Инициализатор словаря
  • Функции сжатые до выражений
C# 7.0[17]
  • out-переменные
  • Сопоставление с шаблоном
  • Шаблоны с is
  • Шаблоны и выражение switch
  • Кортежи
  • Распаковка кортежей (деконструкторы)
  • Локальные функции
  • Улучшения литералов
  • Локальные переменные и возвращаемые значения по ссылке
  • Расширение списка типов, возвращаемых асинхронными методами
  • Больше членов класса в виде выражений
  • throw выражения
C# 8.0
  • Члены только для чтения
  • Члены интерфейса по умолчанию
  • Улучшения сопоставления шаблонов
  • Объявления using
  • Статические локальные функции
  • Удаляемые ссылочные структуры
  • Ссылочные типы, допускающие значение NULL
  • Асинхронные потоки
  • Индексы и диапазоны
  • Присваивание объединения со значением NULL
  • Неуправляемые сконструированные типы
  • Выражения stackalloc во вложенных выражениях
  • Больше членов класса в виде выражений
  • Улучшения интерполированных строк
C# 9.0
  • Оператор объединения с null (??)
  • Пустые параметры для лямбда-выражений
  • Native Int: nint, nuint
  • Дизъюнктное объединение
  • Добавлено with-выражения
  • новый модификатор initonly
C# 10.0
  • Добавление role="alert" атрибуты сообщений
  • ОбновленияCounter компонент для добавления role="status"
  • Замена ul в NavBar компонент для nav
  • Новое название кнопки переключенияNavBar
  • Переход к использованию более семантической разметки
C# 11.0
  • Необработанные строковые литералы
  • Поддержка универсальной математики
  • Универсальные атрибуты
  • Строковые литералы UTF-8
  • Новые строки в выражениях интерполяции строк
  • Шаблоны списка
  • Локальные типы файлов
  • Обязательные элементы
  • Автоматические структуры по умолчанию
  • Сопоставление Span<char> шаблонов для константы string
  • Расширенные nameof область
  • Числовой intPtr
  • ref поля и scoped ref
  • Улучшенное преобразование групп методов для делегирования.

Проект C# был начат в декабре 1998 и получил кодовое название COOL (C-style Object Oriented Language). Версия 1.0 была анонсирована вместе с платформой .NET в июне 2000 года, тогда же появилась и первая общедоступная бета-версия; C# 1.0 окончательно вышел вместе с Microsoft Visual Studio .NET в феврале 2002 года.

Первая версия C# напоминала по своим возможностям Java 1.4, несколько их расширяя: так, в C# имелись свойства (выглядящие в коде как поля объекта, но на деле вызывающие при обращении к ним методы класса), индексаторы (подобные свойствам, но принимающие параметр как индекс массива), события, делегаты, циклы foreach, структуры, передаваемые по значению, автоматическое преобразование встроенных типов в объекты при необходимости (boxing), атрибуты, встроенные средства взаимодействия с неуправляемым кодом (DLL, COM) и прочее.

Кроме того, в C# решено было перенести некоторые возможности C++, отсутствовавшие в Java: беззнаковые типы, перегрузку операторов (с некоторыми ограничениями, в отличие от C++), передача параметров в метод по ссылке, методы с переменным числом параметров, оператор goto (с ограничениями). Также в C# оставили ограниченную возможность работы с указателями — в местах кода, специально обозначенных словом unsafe и при указании специальной опции компилятору.

Проект спецификации C# 2.0 впервые был опубликован Microsoft в октябре 2003 года; в 2004 году выходили бета-версии (проект с кодовым названием Whidbey), C# 2.0 окончательно вышел 7 ноября 2005 года вместе с Visual Studio 2005 и .NET 2.0.

Новые возможности в версии 2.0
  • Частичные типы (разделение реализации класса более чем на один файл).
  • Обобщённые, или параметризованные типы (generics). В отличие от шаблонов C++, они поддерживают некоторые дополнительные возможности и работают на уровне виртуальной машины. Вместе с тем, параметрами обобщённого типа не могут быть выражения, они не могут быть полностью или частично специализированы, не поддерживают шаблонных параметров по умолчанию, от шаблонного параметра нельзя наследоваться, и т. д.[18]
  • Новая форма итератора, позволяющая создавать сопрограммы с помощью ключевого слова yield, подобно Python и Ruby.
  • Анонимные методы, обеспечивающие функциональность замыкания.
  • Оператор null-объединения: '??': return obj1 ?? obj2; означает (в нотации C# 1.0) return obj1!=null ? obj1 : obj2;.
  • Обнуляемые (nullable) типы — значения (обозначаемые вопросительным знаком, например, int? i = null;), представляющие собой те же самые типы-значения, способные принимать также значение null. Такие типы позволяют улучшить взаимодействие с базами данных через язык SQL.
  • Возможность создавать хранимые процедуры, триггеры и даже типы данных на .Net языках (в том числе и на C#).
  • Поддержка 64-разрядных вычислений, что кроме всего прочего, позволяет увеличить адресное пространство и использовать 64-разрядные примитивные типы данных.

В июне 2004 года Андерс Хейлсберг впервые рассказал на сайте Microsoft о планируемых расширениях языка в C#3.0[19]. В сентябре 2005 года вышли проект спецификации C# 3.0 и бета-версия C# 3.0, устанавливаемая в виде дополнения к существующим Visual Studio 2005 и .NET 2.0. Окончательно эта версия языка вошла в Visual Studio 2008 и .NET 3.5.

Новые возможности в версии 3.0

В C# 3.0 появились следующие радикальные добавления к языку:

  • ключевые слова select, from, where, позволяющие делать запросы из XML документов, коллекций и т. п. Эти запросы имеют сходство с запросами SQL и реализуются компонентом LINQ. (Сама фраза «language integrated query» переводится «запрос, интегрированный в язык».)
  • Инициализация объекта вместе с его свойствами:
Customer c = new Customer(); c.Name = "James"; c.Age=30;
можно записать как
Customer c = new Customer { Name = "James", Age = 30 };
listOfFoo.Where(delegate(Foo x) { return x.size > 10; });
теперь можно записать как
listOfFoo.Where(x => x.size > 10);
  • Деревья выражений:
лямбда-выражения теперь могут представляться в виде структуры данных, доступной для обхода во время выполнения, тем самым позволяя транслировать строго типизированные C#-выражения в другие домены (например, выражения SQL).
  • Неявная типизация: Вывод типов локальной переменной. Для неявной типизации вместо названия типа данных используется ключевое слово var. Затем уже при компиляции компилятор сам выводит тип данных исходя из присвоенного значения:var x = "hello"; вместо string x = "hello";
  • Анонимные типы: var x = new { Name = "James" };
  • Методы расширения. Появилась возможность добавления новых методов в уже существующие классы. Реализуется с помощью ключевого слова this при первом параметре статической функции статического класса.
public static class StringExtensions
{
  public static int ToInt32(this string val)
  {
    return Int32.Parse(val);
  }
}
// ...
string s = "10";
int x = s.ToInt32();
  • Автоматические свойства: компилятор сгенерирует закрытое (private) поле и соответствующие аксессор и мутатор для кода вида
public string Name { get; private set; }

C# 3.0 совместим с C# 2.0 по генерируемому MSIL-коду; улучшения в языке — чисто синтаксические и реализуются на этапе компиляции. Например, многие из интегрированных запросов LINQ можно осуществить, используя безымянные делегаты в сочетании с предикатными методами над контейнерами наподобие List.FindAll и List.RemoveAll.

Превью C# 4.0 было представлено в конце 2008 года, вместе с CTP-версией Visual Studio 2010.

Visual Basic 10.0 и C# 4.0 были выпущены в апреле 2010 года, одновременно с выпуском Visual Studio 2010.

Новые возможности в версии 4.0[20]
  • Возможность использования позднего связывания, для использования:
    • с языками с динамической типизацией (Python, Ruby)
    • с COM-объектами
    • отражения (reflection)
    • объектов с изменяемой структурой (DOM). Появляется ключевое слово dynamic.
  • Именованные и опциональные параметры
  • Новые возможности COM interop
  • Ковариантность и контравариантность обобщенных интерфейсов и делегатов
  • Контракты в коде (Code Contracts)
  • Библиотека параллельных задач TPL (Task Parallel Library), концепция задач и классы Task, TaskFactory, Parallel
  • Добавлен класс MemoryCache, который предназначен для кэширования контента. Он похож на класс Cache ASP.NET, но его можно использовать при написании веб- / графических / консольных приложений.
  • Добавлено пространство имен System.Collections.Concurrent и новые классы параллельных коллекций (ConcurrentQueue, ConcurrentStack, ConcurrentBag,…), которые предоставляют не только большую эффективность, но и более полную потокобезопасность.

Примеры:

dynamic calc = GetCalculator();
int sum = calc.Add(10, 20); // Динамический вызов
public void SomeMethod(int x, int y = 5, int z = 7); // Опциональные параметры

Новые возможности в версии 5.0

  • Шаблон TAP (Task-based Asynchronous Pattern). TAP использует один метод для представления инициализации и завершения асинхронной операции.
  • Асинхронные методы (async и await) — как реализация шаблона TAP.
  • Сведения о вызывающем объекте

Новые возможности в версии 6.0

  • null-условные операторы. Добавлены новые операторы: ?. и ?[]:
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0];  // null if customers is null
  • Функции сжатые до выражений (expression-bodied functions). Теперь определение метода может быть задано с использованием лямбда-синтаксиса:
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
  • Инициализаторы автосвойств. Автосвойства теперь можно инициализировать при объявлении:
public string First { get; set; } = "Jane";
  • Автосвойства только для чтения. Автосвойства теперь могут быть объявлены без сеттеров:
public string First { get; } = "Jane";
  • Инициализаторы индексов. Теперь можно инициализировать не только объекты и коллекции, но и словари:
var numbers = new Dictionary<int, string> {
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};
  • Интерполяция строк. Вместо использования конструкций с String.Format(), например:
var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);

теперь можно размещать код прямо в строке:

var s = $"{p.Name} is {p.Age} year{{s}} old";
  • Фильтры исключений. Появилась возможность задавать условия для блоков catch:
try {  } catch (Exception e) when (Log(e)) {  }
  • Импорт статических функций типов. Теперь доступ к статическим членам типов возможен без указания полного имени этих членов:
using static System.Console;
using static System.Math;
class Program
{
    static void Main()
    {
        WriteLine(Sqrt(3*3 + 4*4)); 
    }
}
  • Оператор nameof. Новый оператор, который возвращает компактное строковое представление для переданного в качестве аргумента типа:
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"
  • Для асинхронного программирования была добавлена возможность использования операторов await внутри блоков catch и finally:
Resource res = null;
try
{
    res = await Resource.OpenAsync();       // You could do this.
} 
catch(ResourceException e)
{
    await Resource.LogAsync(res, e);         // Now you can do this …
}
finally
{
    if (res != null) await res.CloseAsync(); // … and this.
}

Новые возможности в версии 7.0[17]

  • out-переменные, которые позволяют объявить переменные сразу в вызове метода (причем областью видимости для таких переменных является внешний блок):
p.GetCoordinates(out int x, out int y);
  • Сопоставление с шаблоном. Вводится понятие шаблона (pattern), который представляет собой синтаксическую конструкцию, позволяющую проверить соответствие переменной определённой форме и извлечь из неё информацию.
  • Шаблоны с is (is теперь может использоваться не только с типом, но и с шаблоном — в качестве правого аргумента)
  • Шаблоны и выражение switch. Варианты использования switch были расширены, теперь можно:
    • использовать любые типы (не только примитивные);
    • использовать шаблоны в выражениях case;
    • добавлять дополнительные условия к выражениям case (используя ключевое слово when).
  • Кортежи. Добавлен тип кортеж значений (структура ValueTuple) и синтаксис работы с данными этого типа:
(string, string, string) LookupName(long id) // возвращаемый тип - кортеж
{
    ... // инициализируем данные
    return (first, middle, last); // литерал кортежа
}
  • Распаковка кортежей. Была добавлена новая синтаксическая конструкция деконструктор, позволяющая извлечь кортеж, состоящий из членов класса.
  • Локальные функции. Теперь функцию, которая используется только в теле какого-либо метода, можно объявить прямо в теле этого метода.
  • Улучшения литералов. Были добавлены бинарные литералы и символ разделителя (_) в числовых литералах.
  • Локальные переменные и возвращаемые значения по ссылке. Расширена функциональность ключевого слова ref. Теперь можно возвратить данные из метода или сохранить их в локальной переменной по ссылке.
  • Расширение списка типов, возвращаемых асинхронными методами
  • Больше членов класса в виде выражений. Синтаксис функций, сжатых до выражений (expression-bodied functions), теперь применим для сеттеров, геттеров, конструкторов и деструкторов.
  • throw-выражения. Теперь можно использовать throw в функциях, сжатых до выражений (expression-bodied functions):
public string GetLastName() => throw new NotImplementedException();

Новые возможности в версии 8.0[21]

  • Модификатор readonly. Был создан для обозначения члена, который не изменит состояние.
  • Методы интерфейсов по умолчанию. Теперь при создании метода интерфейса можно объявить его реализацию по умолчанию, которую можно переопределить в классе, который реализует этот интерфейс.
  • Сопоставление шаблонов. Возможность позволяет работать с шаблонами в зависимости от формата в связанных, но различных типах данных.
    • Рекурсивные шаблоны. Является выражением шаблона, которое применяется к результатам другого выражения шаблона.
    • Выражения switch позволяют сократить количество case и break, а также фигурных скобок.
      public enum Rainbow
      {
          Red,
          Orange,
          Yellow,
          Green,
          Blue,
          Indigo,
          Violet
      }
      
      public static RGBColor FromRainbow(Rainbow colorBand) =>
          colorBand switch
          {
              Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
              Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
              Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
              Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
              Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
              Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
              Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
              _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
          };
      
    • Шаблоны свойств. Позволяет сопоставлять свойства исследуемого объекта с помощью { variable : value } => ... .
    • Шаблоны кортежей. Используется, если нужно работать с несколькими наборами входных данных. (value1, value2,..) => ...
  • Объявление using. Это объявление переменной, которому предшествует ключевое слово using. Оно сообщает компилятору, что объявляемая переменная должна быть удалена в конце области видимости.
  • Статический локальный метод. Теперь можно убедиться в том, что метод не охватывает какие-либо переменные из области видимости с помощью добавления к нему модификатора static.
  • Удаляемые ссылочные структуры. Ссылочные структуры не могут реализовать IDisposable (как и любые другие интерфейсы). Поэтому чтобы удалить ref struct, необходим доступный void Dispose().
  • Типы значений, допускающие значение null. Теперь, чтобы указать, что переменная типа значений допускает значение null, необходимо поставить к имени типа ?
  • Асинхронные потоки. Это во-первых интерфейс IAsyncEnumerable<T>. А во-вторых конструкция foreach с await.
    public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
    {
        for (int i = 0; i < 20; i++)
        {
            await Task.Delay(100);
            yield return i;
        }
    }
    // or
    await foreach (var number in GenerateSequence())
    {
        Console.WriteLine(number);
    }
    
  • Асинхронные высвобождаемые типы. Начиная с C# 8.0 язык поддерживает асинхронные освобождаемые типы, реализующие интерфейс System.IAsyncDisposable. Операнд выражения using может реализовывать IDisposable или IAsyncDisposable. В случае IAsyncDisposable компилятор создает код для await, возвращенного Task из IAsyncDisposable.DisposeAsync.
  • Индексы и диапазоны. Диапазоны и индексы обеспечивают лаконичный синтаксис для доступа к отдельным элементам или диапазонам в последовательности. Нововведение включает в себя операторы ^ и .. , а также System.Index и System.Range
  • Оператор присваивания объединения с null. Оператор ??= можно использовать для присваивания значения правого операнда левому операнду только в том случае, если левый операнд имеет значение null.
    List<int> numbers = null;
    int? i = null;
    
    numbers ??= new List<int>();
    numbers.Add(i ??= 17);
    numbers.Add(i ??= 20);
    
    Console.WriteLine(string.Join(" ", numbers));  // output: 17 17
    Console.WriteLine(i);  // output: 17
    
  • Неуправляемые сконструированные типы. Начиная с C# 8.0, сконструированный тип значения является неуправляемым, если он содержит поля исключительно неуправляемых типов (например универсальный тип <T>).
  • Выражение stackalloc во вложенных выражениях. Теперь если результат выражения stackalloc имеет тип System.Span<T> или System.ReadOnlySpan<T>, то его можно использовать в других выражениях.
    Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
    var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6, 8 });
    Console.WriteLine(ind);  // output: 1
    
  • Порядок маркеров $ и @ в интерполированных строках verbatim теперь может быть любым.

Новые возможности в версии 9.0[22]

  • Типы записей. Появилась возможность при помощи ключевого слова record для определения ссылочного типа, предоставляющего функционал инкапсуляции данных.
    public record Person(string FirstName, string LastName);
    
    По умолчанию типы записей является неизменяемыми. В отличие от других ссылочных типов, переменные типов записей считаются равными, если равны типы и значения их свойств и полей.
    • Обратимые изменения. Для заданного экземпляра записи при помощи ключевого слова with возможно создание копии с изменёнными значениями указанных свойств и полей.
    • Запись может быть унаследована от записи. Однако запись не может быть унаследована от класса, и наоборот, класс не может быть унаследован от записи.
  • Инициализаторы. C# 9.0 предоставляет синтаксис — ключевое слово init — для задания значений свойств класса при инициализации.
    public class Person
    {
        public string FirstName { get; init; }
        public string LastName { get; init; }
    };
    
  • Операторы верхнего уровня. Один файл в приложении допускается начать сразу с исполняемых строк кода, минуя ряд таких формальностей, как объявление пространств имён, классов, методов. Такие операторы эквивалентны операторам метода Main.
  • Улучшения сопоставлений шаблонов.
    • Шаблоны типов — соответствуют объекту заданного типа.
    • Логические шаблоны — входные данные должны соответствовать заданной логической операции (and, or, not).
    • Реляционные шаблоны — входные данные должны соответствовать заданной операции сравнения (больше, меньше, равно, больше или равно, меньше или равно) с константой.
  • Улучшения производительности.
  • Допускается опустить тип создаваемого объекта в выражении new, если он известен заранее
    private List<Person> persons = new();
    
  • Поддержка статических лямбда-выражений и статических анонимных методов. Как и статические локальные функции, они не могут захватывать нестатические локальные переменные и состояния экземпляра.
  • Поддержка применения атрибутов к локальным функциям.

Новые возможности в версии 10.0[23]

  • Глобальные импорты. С помощью ключевого слова global появилась возможность определить пространства имён, которые будут импортированы глобально во всех файлах проекта.
    global using System;
    global using System.Collections.Generic;
    
  • Файловая область видимости пространства имён. Объявление пространства имён может быть применено ко всему файлу, что уменьшает уровень отступов в коде.
    namespace MyNamespace;
    
  • Усовершенствованные структуры. Добавлены улучшения в работу со структурами, в том числе возможность инициализации полей непосредственно в теле структуры и поддержка параметров по умолчанию.
    public struct Point
    {
        public int X { get; set; } = 0;
        public int Y { get; set; } = 0;
    }
    
  • Запечатанные интерфейсы. Интерфейсы могут быть объявлены как sealed, что предотвращает их реализацию другими интерфейсами.
    public sealed interface IMyInterface { }
    
  • Усовершенствованные операторы и литералы. Поддержка with-оператора для структурных типов, улучшенные string-интерполяции и другие синтаксические улучшения.
  • Улучшенное сопоставление шаблонов. Добавлены новые возможности для сопоставления шаблонов, включая шаблоны списков и возможность использования шаблонов в операторах switch и if.
    int[] numbers = { 1, 2, 3, 4, 5 };
    bool isThreeElementArray = numbers is [_, _, _];
    
  • Поддержка записи структуры и членов записи. Улучшена производительность при использовании структурных типов с поддержкой записи.
    public record struct Point(int X, int Y);
    
  • Усовершенствованные атрибуты. Возможность применения атрибутов к более широкому кругу элементов, таких как локальные функции и выражения.
    [MyCustom]
    void LocalFunction() { }
    
  • Лямбда-выражения. Поддержка более мощных и гибких лямбда-выражений, включая использование типов возврата и деструктуризацию.
    var increment = (int x) => x + 1;
    
  • Усовершенствованные async/await. Улучшена работа с асинхронными методами, включая более эффективное управление памятью и потоками.

Новые возможности в версии 11.0[24]

  • Статические виртуальные элементы в интерфейсах. Интерфейсы теперь могут включать статические виртуальные и абстрактные члены, что позволяет перегружать операторы и определять статические свойства и методы. Это упрощает реализацию универсальных математических операций.
    public interface IMyInterface<TSelf, TOther, TResult> 
        where TSelf : IMyInterface<TSelf, TOther, TResult> 
    { 
        static abstract TResult operator +(TSelf left, TOther right); 
    }
    
  • Проверяемые и непроверяемые операторы. Разработчики могут определять checked и unchecked арифметические операторы, что позволяет компилятору вызывать правильный вариант на основе контекста.
    public static checked int operator +(MyType left, MyType right)
    {
        left.Value + right.Value; 
    }
    
  • Оператор unsigned right-shift. Введен новый оператор >>>, который выполняет сдвиг вправо без знака, упрощая работу с целочисленными типами.
    int result = -8 >>> 2;
    
  • Ослабленные требования к операторам смены. Второй операнд оператора сдвига больше не обязан быть типа int, что делает использование универсальных математических интерфейсов более гибким.
    MyType value = new MyType();
    value >>= 3;
    
  • Поддержка универсальной математики. Новые интерфейсы, такие как System.IAdditionOperators<TSelf, TOther, TResult>, позволяют типам реализовывать математические операции более последовательно и удобно.
    public struct MyNumber : IAdditionOperators<MyNumber, MyNumber, MyNumber> 
    { 
        public static MyNumber operator +(MyNumber left, MyNumber right)
        {
            new MyNumber(left.Value + right.Value);
        }
    }
    
  • Расширенные возможности инициализации типов. Теперь можно задавать значения полей прямо в теле структуры и использовать параметры по умолчанию.
    public struct Point 
    { 
        public int X { get; set; } = 0; 
        public int Y { get; set; } = 0; 
    }
    

Новые возможности в версии 12.0[25]

  • Статические абстрактные и виртуальные методы в интерфейсах. Интерфейсы теперь могут содержать статические абстрактные и виртуальные методы, что позволяет определять поведение для универсальных математических операций.
    public interface IMyInterface<TSelf, TOther, TResult> 
        where TSelf : IMyInterface<TSelf, TOther, TResult> 
    { 
        static abstract TResult operator +(TSelf left, TOther right); 
        static virtual TResult Add(TSelf left, TOther right) 
        {
            return left + right;
        }
    }
    
  • Поддержка коллекций с неизменяемыми элементами. Введена новая коллекция ImmutableArray, которая обеспечивает неизменяемость элементов и повышение производительности.
    var immutableArray = ImmutableArray.Create(1, 2, 3, 4);
    
  • Улучшенные структуры данных. В C# 12 введены новые типы данных, такие как readonly struct и ref readonly struct, для оптимизации работы с памятью.
    public readonly struct Point 
    { 
        public int X { get; } 
        public int Y { get; }
    
        public Point(int x, int y) 
        {
            X = x;
            Y = y;
        }
    }
    
  • Расширенные возможности для типов записи. Теперь записи поддерживают наследование и могут содержать методы с телами.
    public record Person(string Name) 
    { 
        public virtual string GetName() => Name;
    }
    
    public record Employee(string Name, int EmployeeId) : Person(Name) 
    { 
        public override string GetName() => $"{Name} (ID: {EmployeeId})";
    }
    
  • Поддержка типов с произвольным количеством параметров. Введены новые методы для работы с переменным числом параметров, упрощая использование таких типов в коде.
    public void PrintValues(params int[] values) 
    { 
        foreach (var value in values) 
        {
            Console.WriteLine(value);
        }
    }
    
    PrintValues(1, 2, 3, 4);
    
  • Расширенные возможности компилятора. В C# 12 компилятор получил новые возможности для оптимизации и проверки кода, включая улучшенную поддержку анализаторов и генераторов исходного кода.

Пример «Hello, World!»

[править | править код]

Ниже представлен код классической программы «Hello world» на C# для консольного приложения:

Console.WriteLine("Hello World!");

и код этой же программы для приложения Windows Forms:

namespace WindowsForms;

public class Program
{
    [STAThread]
    public static void Main() => new DemoForm().ShowDialog();
}

public class DemoForm : Form
{
    Label label = new Label();

    public DemoForm()
    {
        label.Text = "Hello World!";
        this.Controls.Add(label);
        this.StartPosition = FormStartPosition.CenterScreen;
        this.BackColor = Color.White;
        this.FormBorderStyle = FormBorderStyle.Fixed3D;
    }
}

Реализации

[править | править код]

Существует несколько реализаций C#:

Примечания

[править | править код]
  1. «Поскольку язык С# унаследовал свой синтаксис от C++ и Java…» Трей Нэш. C# 2010: ускоренный курс для профессионалов = Accelerated C# 2010. — М.: Вильямс, 2010. — С. 17. — 592 с. — ISBN 978-5-8459-1638-9.
  2. «Язык C# <…> унаследовал много полезных возможностей от других языков программирования и напрямую связан с двумя наиболее широко применяемыми в мире компьютерными языками — C и C++, а также с языком Java», однако далее: «Связь между C# и Java более сложная. Оба языка разработаны для создания переносимого кода, базируются на C и C++, используют их синтаксис и объектную модель. Однако между этими языками нет прямой связи, они больше похожи на двоюродных братьев, имеющих общих предков, но отличающихся многими признаками» Герберт Шилдт. C# учебный курс = C#. A Beginner's Guide. — М.: Питер, 2003. — С. 20. — ISBN 966-552-121-7.
  3. Герберт Шилдт. Полный справочник по С# = C#: The Complete Reference. — М.: Издательский дом «Вильямс», 2004. — С. 26—27. — 752 с. — ISBN 5-8459-0563-X.
  4. Лицензия (Roslyn) в репозитории Github. Дата обращения: 4 января 2022. Архивировано 4 января 2022 года.
  5. Лицензия (.NET CLR) в репозитории Github. Дата обращения: 4 января 2022. Архивировано 4 января 2022 года.
  6. Либерти Д. Язык программирования C# // Программирование на C#. — Санкт-Петербург. — 2003: Символ-Плюс, 2003. — С. 26. — 688 с. — ISBN 5-93286-038-3.
  7. Kovacs, James C#/.NET History Lesson (англ.) (7 сентября 2007). Дата обращения: 23 марта 2011. Архивировано 21 августа 2011 года.
  8. The A-Z of Programming Languages: C# (англ.). computerworld.com.au (1 октября 2008). Дата обращения: 2 сентября 2014. Архивировано из оригинала 2 апреля 2015 года.
  9. Microsoft C# FAQ. Microsoft. Дата обращения: 25 марта 2008. Архивировано 30 апреля 2003 года.
  10. C# Language Specification (неопр.). — 4th. — Ecma International, 2006. Архивировано 2 декабря 2012 года. Архивированная копия. Дата обращения: 26 января 2011. Архивировано 2 декабря 2012 года.
  11. Visual C#.net Standard (JPEG). Microsoft (4 сентября 2003). Дата обращения: 18 июня 2009. Архивировано 21 августа 2011 года.
  12. Standard ECMA-334 C# Language Specification, 4rd edition (англ.). Ecma International (июнь 2006). Дата обращения: 16 мая 2017. Архивировано 31 октября 2010 года.
  13. ISO/IEC 23270:2003 Information technology -- C# Language Specification (англ.). International Organization for Standardization (апрель 2003). Дата обращения: 16 мая 2017. Архивировано 5 августа 2017 года.
  14. Спецификация по Microsoft C# 2.0 содержит описание лишь новых возможностей версии 2.0. Особенности версии описаны в спецификации 1.2, приведенной выше.
  15. Для версий языка C# 3.0, 4.0 и 5.0 пока нет утверждённых ECMA или ISO/IEC спецификаций.
  16. Заметки релиза Visual Studio 2022 17.8. Microsoft Learn. Дата обращения: 29 июня 2023. Архивировано 6 августа 2023 года.
  17. 1 2 Mads Torgersen. New Features in C# 7.0 (англ.). .NET Blog. Microsoft (9 марта 2017). Дата обращения: 7 мая 2017. Архивировано 11 апреля 2017 года.
  18. Differences Between C++ Templates and C# Generics (C# Programming Guide) (англ.). Microsoft (17 декабря 2016). Дата обращения: 16 мая 2017. Архивировано 7 августа 2021 года.
  19. Anders Hejlsberg - Programming data in C# 3.0 (англ.). The Channel 9 Team. Microsoft (16 июня 2004). Дата обращения: 16 мая 2017. Архивировано 12 ноября 2018 года.
  20. Visual Studio 2010: примеры для C# 4.0. Microsoft (17 июля 2012). Дата обращения: 16 мая 2017. Архивировано 28 февраля 2017 года.
  21. Новые возможности C# 8.0. docs.microsoft.com. Дата обращения: 11 июня 2020. Архивировано 8 августа 2020 года.
  22. Новые возможности C# 9.0. docs.microsoft.com. Дата обращения: 29 апреля 2023. Архивировано 8 декабря 2022 года.
  23. Новые возможности C# 10.0. docs.microsoft.com. Дата обращения: 11 апреля 2023. Архивировано 8 декабря 2022 года.
  24. Новые возможности C# 11.0. docs.microsoft.com. Дата обращения: 1 июня 2024. Архивировано 20 декабря 2023 года.
  25. Новые возможности C# 12.0. docs.microsoft.com. Дата обращения: 3 марта 2024. Архивировано 21 декабря 2023 года.
  26. Dot Net Anywhere. Дата обращения: 5 марта 2009. Архивировано 4 мая 2009 года.

Литература

[править | править код]