Jump to content

Синтаксис C Sharp

В этой статье описывается синтаксис языка C# программирования . Описанные функции совместимы с .NET Framework и Mono .

Идентификатор

[ редактировать ]

Идентификатор это имя элемента в коде . Он может содержать буквы, цифры и символы подчеркивания ( _) и чувствителен к регистру ( FOO отличается от foo). Язык накладывает следующие ограничения на имена идентификаторов:

  • Они не могут начинаться с цифры;
  • Они не могут начинаться с символа, если только это не ключевое слово;
  • Они не могут содержать более 511 символов .

Имена идентификаторов могут начинаться с знака at ( @), но это незначительно; @name тот же идентификатор, что и name.

Microsoft опубликовала соглашения об именах для идентификаторов в C#, которые рекомендуют использовать PascalCase для имен типов и большинства членов типов, а также CamelCase для переменных и частных или внутренних полей. [1] Однако эти соглашения об именах не соблюдаются в языке.

Ключевые слова

[ редактировать ]

Ключевые слова — это заранее определенные зарезервированные слова со специальным синтаксическим значением. [2] В языке есть два типа ключевых слов — контекстные и зарезервированные. Зарезервированные ключевые слова, такие как false или byte могут использоваться только в качестве ключевых слов. Контекстные ключевые слова, такие как where или from рассматриваются как ключевые слова только в определенных ситуациях. [3] Если необходим идентификатор, аналогичный зарезервированному ключевому слову, для его различения перед ним можно поставить знак at. Например, @out интерпретируется как идентификатор, тогда как out как ключевое слово. Этот синтаксис облегчает повторное использование кода .NET , написанного на других языках. [4]

Следующие ключевые слова C# являются зарезервированными словами: [2]

  • abstract
  • as
  • base
  • bool
  • break
  • byte
  • case
  • catch
  • char
  • checked
  • class
  • const
  • continue
  • decimal
  • default
  • delegate
  • do
  • double
  • else
  • enum
  • event
  • explicit
  • extern
  • false
  • finally
  • fixed
  • float
  • for
  • foreach
  • goto
  • if
  • implicit
  • in
  • int
  • interface
  • internal
  • is
  • lock
  • long
  • namespace
  • new
  • null
  • object
  • operator
  • out
  • override
  • params
  • private
  • protected
  • public
  • readonly
  • ref
  • return
  • sbyte
  • sealed
  • short
  • sizeof
  • stackalloc
  • static
  • string
  • struct
  • switch
  • this
  • throw
  • true
  • try
  • typeof
  • uint
  • ulong
  • unchecked
  • unsafe
  • ushort
  • using
  • virtual
  • void
  • volatile
  • while

Контекстное ключевое слово используется для придания определенного значения в коде, но оно не является зарезервированным словом в C#. Некоторые контекстные ключевые слова, такие как partial и where, имеют особое значение в различных контекстах. Следующие ключевые слова C# являются контекстными: [5]

  • add
  • and
  • alias
  • ascending
  • args
  • async
  • await
  • by
  • descending
  • dynamic
  • equals
  • from
  • get
  • global
  • group
  • init
  • into
  • join
  • let
  • managed
  • nameof
  • nint
  • not
  • notnull
  • nuint
  • on
  • or
  • orderby
  • partial
  • record
  • remove
  • required
  • select
  • set
  • unmanaged
  • value
  • var
  • when
  • where
  • with
  • yield

Литералы

[ редактировать ]
Целые числа
десятичный 23456, [0..9]+
шестнадцатеричный 0xF5, 0x[0..9, A..F, a..f]+
двоичный 0b010110001101, 0b[0,1]+
с плавающей запятой Значения
плавать 23.5F, 23.5f; 1.72E3F, 1.72E3f, 1.72e3F, 1.72e3f
двойной 23.5, 23.5D, 23.5d; 1.72E3, 1.72E3D, ...
десятичный 79228162514264337593543950335m, -0.0000000000000000000000000001m, ...
Персонажи
голец 'a', 'Z', '\u0231', '\x30', '\n'
Струны
нить "Hello, world"
"C:\\Windows\\", @"C:\Windows\" [дословные строки (перед которыми стоит @) могут включать символы разрыва строки и возврата каретки]
$"Hello, {name}!" Интерполированная строка. В виде дословной строки: $@"Hello, {name}!"
Экранирование символов в строках
Юникода Символ \u за которым следует шестнадцатеричный код Юникода
Расширенный_ASCII- символ \x за которым следует шестнадцатеричный расширенный код ASCII
Нулевой символ [а] \0
Вкладка \t
Backspace \b
Возврат каретки \r
Подача формы \f
обратная косая черта \\
Одиночная цитата \'
Двойная кавычка \"
Перевод строки \n
  1. ^ В C# строки не завершаются нулем , поэтому нулевые символы могут появляться в любом месте строки.

Разделители цифр

[ редактировать ]

Начиная с C# 7.0, символ подчеркивания можно использовать для разделения цифр в числовых значениях в целях удобства чтения. Компилятор игнорирует эти подчеркивания.

int bin = 0b1101_0010_1011_0100;
int hex = 0x2F_BB_4A_F1;
int dec = 1_000_500_954;
double real = 1_500.200_2e-1_000;

Как правило, его можно помещать только между цифрами. Его нельзя ставить в начало( _121) или конец значения ( 121_ или 121.05_), рядом с десятичной дробью в значениях с плавающей запятой ( 10_.0), рядом с символом экспоненты ( 1.1e_1) или рядом со спецификатором типа ( 10_f).

Переменные

[ редактировать ]

Переменные — это идентификаторы, связанные со значениями. Они объявляются путем записи типа и имени переменной и при необходимости инициализируются в том же операторе.

Объявить

int myInt;         // Declaring an uninitialized variable called 'myInt', of type 'int'

Назначение

int myInt;        // Declaring an uninitialized variable
myInt = 35;       // Assigning the variable a value

Инициализировать

int myInt = 35;   // Declaring and initializing the variable

Несколько переменных одного типа могут быть объявлены и инициализированы в одном операторе.

int a, b;         // Declaring multiple variables of the same type

int a = 2, b = 3; // Declaring and initializing multiple variables of the same type

Вывод типа локальной переменной

[ редактировать ]
Это особенность C# 3.0 .

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

var myChars = new char[] {'A', 'Ö'}; // or char[] myChars = new char[] {'A', 'Ö'};

var myNums = new List<int>();  // or List<int> myNums = new List<int>();

Константы

[ редактировать ]

Константы — это неизменяемые значения.

При объявлении локальной переменной или поля с const ключевое слово в качестве префикса, значение должно быть указано при его объявлении. После этого он заблокирован и не может быть изменен. Их можно объявить в контексте как поле или локальную переменную. Константы неявно статичны.

const double PI = 3.14;

Это показывает оба варианта использования ключевого слова.

public class Foo
{
    private const double X = 3;

    public Foo()
    {
        const int y = 2;
    }
}

The readonly Ключевое слово делает то же самое, что и поля. Как и поля, отмеченные как const они не могут измениться после инициализации. Разница в том, что вы можете инициализировать их в конструкторе или использовать значение, неизвестное до момента выполнения. Это работает только на полях. readonly поля могут быть либо членами экземпляра, либо членами статического класса.

Блоки кода

[ редактировать ]

Фигурные скобки { ... } используются для обозначения блока кода и новой области действия . Члены класса и тело метода являются примерами того, что может находиться внутри этих фигурных скобок в различных контекстах.

Внутри тел методов вы можете использовать фигурные скобки для создания новых областей следующим образом:

void DoSomething()
{
    int a;

    {
        int b;
        a = 1;
    }

    a = 2;
    b = 3; // Will fail because the variable is declared in an inner scope.
}

Структура программы

[ редактировать ]

Приложение AC# состоит из классов и их членов. Классы и другие типы существуют в пространствах имен, но также могут быть вложены в другие классы.

Основной метод

[ редактировать ]

Будь то консольное или графическое приложение, программа должна иметь какую-то точку входа. Точкой входа в приложение C# является метод под названием Main. Может быть только один, и это статический метод в классе. Обычно метод возвращает void и передается аргументы командной строки в виде массива строк.

static void Main(string[] args)
{
}
// OR Main method can be defined without parameters.
static void Main()
{
}

Основной метод также может возвращать целочисленное значение, если оно указано.

static int Main(string[] args)
{
    return 0;
}

Асинхронная основная

[ редактировать ]

Это особенность C# 7.1.

Асинхронные задачи можно ожидать в Main метод, объявив его возвращаемым типом Task.

static async Task Main(string[] args)
{
    await DoWorkAsync(42);
}

Все комбинации из Task, или Task<int>, и с или без string[] args параметр поддерживаются.

Заявления высшего уровня

[ редактировать ]

Это особенность C# 9.0.

Как и в языках сценариев, операторы верхнего уровня устраняют необходимость объявлять Program класс с Main метод.

Вместо этого операторы могут быть записаны непосредственно в один конкретный файл, и этот файл будет точкой входа программы. Код в других файлах все равно придется определять в классах.

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

using System;

Console.WriteLine("Hello World!");

Типы объявляются после операторов и будут автоматически доступны из операторов над ними.

Пространства имен

[ редактировать ]

Пространства имен являются частью имени типа и используются для группировки и/или отличия именованных сущностей от других.

System.IO.DirectoryInfo // DirectoryInfo is in the System.IO-namespace

Пространство имен определяется следующим образом:

namespace FooNamespace
{
    // Members
}

using директива

[ редактировать ]

The using Директива загружает определенное пространство имен из указанной сборки. Обычно он размещается в верхней части (или заголовке) файла кода, но при желании его можно разместить в другом месте, например, внутри классов. [ нужна ссылка ]

using System;
using System.Collections;

Директиву также можно использовать для определения другого имени для существующего пространства имен или типа. Иногда это полезно, когда имена слишком длинные и менее читабельные.

using Net = System.Net;
using DirInfo = System.IO.DirectoryInfo;

using static директива

[ редактировать ]

using static Директива загружает статические члены указанного типа в текущую область, делая их доступными непосредственно по имени члена.

using static System.Console;

WriteLine("Hello, World!");

Операторы

[ редактировать ]
Категория оператора Операторы
Арифметика +, -, *, /, %
Логический (логический и побитовый) &, |, ^, !, ~, &&, ||, true, false
Конкатенация строк +
Увеличение, уменьшение ++, --
Сдвиг <<, >>
Реляционный (условный) ==, !=, <, >, <=, >=
Назначение =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
Доступ участников ., ?., ?[]
Индексирование []
Бросать ()
Условный (троичный) ?:
Объединение и удаление делегатов +, -
Создание объекта new
Введите информацию as, is, sizeof, typeof
Контроль исключений переполнения checked, unchecked
Косвенность и адрес *, ->, [], &
Слияние ??
Лямбда-выражение =>

Перегрузка оператора

[ редактировать ]

Некоторые из существующих операторов можно перегрузить, написав метод перегрузки.

public static Foo operator+(Foo foo, Bar bar)
{
    return new Foo(foo.Value + bar.Value);
}

Это перегружаемые операторы :

Операторы
+, -, !, ~, ++, --, true, false Унарные операторы
+, -, *, /, %, &, |, ^, <<, >> Бинарные операторы
==, !=, <, >, <=, >= Операторы сравнения должны быть перегружены парами.
  • Операторы присваивания ( +=, *= и т. д.) представляют собой комбинации бинарного оператора и оператора присваивания ( =) и будет оцениваться с использованием обычных операторов, которые можно перегрузить.
  • Операторы приведения ( ( )) нельзя перегрузить, но можно определить операторы преобразования.
  • Индексация массива ( [ ]) не перегружается, но вы можете определить новые индексаторы.

Операторы преобразования

[ редактировать ]

Оператор приведения не является перегружаемым, но вы можете написать метод оператора преобразования, который находится в целевом классе. Методы преобразования могут определять две разновидности операторов: неявные и явные операторы преобразования. Неявный оператор будет выполнять приведение без указания оператора приведения ( ( )), и явный оператор требует его использования.

Оператор неявного преобразования

class Foo
{
    public int Value;

    public static implicit operator Foo(int value)
    {
        return new Foo(value);
    }
}
// Implicit conversion
Foo foo = 2;

Оператор явного преобразования

class Foo
{
    public int Value;

    public static explicit operator Foo(int value)
    {
        return new Foo(value);
    }
}
// Explicit conversion
Foo foo = (Foo)2;

as оператор

[ редактировать ]

The as Оператор попытается выполнить тихое приведение к заданному типу. Если возможно, он вернет объект как новый тип, в противном случае вернет значение null.

Stream stream = File.Open(@"C:\Temp\data.dat");
FileStream fstream = stream as FileStream; // Will return an object.

String str = stream as String; // Will return null.

Нулевой оператор объединения

[ редактировать ]
Это особенность C# 2.0 .

Следующее:

return ifNotNullValue ?? otherwiseValue;

является сокращением для:

return ifNotNullValue != null ? ifNotNullValue : otherwiseValue;

Это означает, что если содержимое переменной ifNotNullValue не равно нулю, это содержимое будет возвращено, в противном случае содержимое переменной otherwiseValue возвращается.

В C# 8.0 введено присваивание с нулевым объединением , так что

variable ??= otherwiseValue;

эквивалентно

if (variable is null) variable = otherwiseValue;

Структуры управления

[ редактировать ]

C# наследует большую часть управляющих структур C/C++, а также добавляет новые, такие как foreach заявление.

Условные структуры

[ редактировать ]

Эти структуры управляют ходом программы в заданных условиях.

if заявление

[ редактировать ]

The if Оператор вводится, когда данное условие истинно. Однострочные операторы case не требуют блочных скобок, хотя по соглашению это обычно предпочтительнее.

Простое заявление в одну строку:

if (i == 3) ... ;

Многострочный с блоком else (без фигурных скобок):

if (i == 2)
    ...
else
    ...

Рекомендуемые соглашения о кодировании для оператора if.

if (i == 3)
{
    ...
}
else if (i == 2)
{
    ...
}
else
{
    ...
}

switch заявление

[ редактировать ]

The switch Конструкция служит фильтром для разных значений. Каждое значение ведет к «случайу». Не допускается пропуск разделов регистра и, следовательно, ключевого слова break обычно используется для завершения дела. Безоговорочный return В разделе дела также можно использовать для завершения дела. Смотрите также, как goto утверждение может использоваться для перехода от одного случая к другому. Однако многие случаи могут привести к одному и тому же коду. Случай по умолчанию обрабатывает все остальные случаи, не обрабатываемые этой конструкцией.

switch (ch)
{
    case 'A':
        statement;
        ...
        break;
    case 'B':
        statement;
        break;
    case 'C': // A switch section can have multiple case labels.
    case 'D':
        ...
        break;
    default:
        ...
        break;
}

Структуры итераций

[ редактировать ]

Операторы итерации — это операторы, которые выполняются повторно, когда заданное условие оценивается как истинное.

while петля

[ редактировать ]
while (i == true)
{
    ...
}

do ... while петля

[ редактировать ]
do
{

}
while (i == true);

The for Цикл состоит из трех частей: объявления , условия и выражения счетчика . Любой из них можно исключить, поскольку он не является обязательным.

for (int i = 0; i < 10; i++)
{
    ...
}

Эквивалентно этому коду, представленному while заявление, за исключением здесь i переменная не является локальной для цикла.

int i = 0;
while (i < 10)
{
    //...
    i++;
}

foreach петля

[ редактировать ]

The foreach заявление вытекает из for оператор и использует определенный шаблон, описанный в спецификации языка C#, чтобы получить и использовать перечислитель элементов для перебора.

Каждый элемент в данной коллекции будет возвращен и доступен в контексте блока кода. Когда блок будет выполнен, следующий элемент будет возвращен до тех пор, пока не останется элементов.

foreach (int i in intList)
{
    ...
}

Операторы перехода

[ редактировать ]

Операторы перехода наследуются от C/C++ и, в конечном итоге, от языков ассемблера. Они просто представляют собой инструкции перехода на языке ассемблера, которые управляют ходом выполнения программы.

Этикетки и goto заявление

[ редактировать ]

Меткам присваиваются точки кода, к которым можно перейти с помощью goto заявление.

start:
    .......
    goto start;

Обратите внимание, что метку не обязательно располагать после goto заявление; это может быть раньше в исходном файле.

The goto заявление можно использовать в switch утверждения перескакивать от одного падежа к другому или переходить от одного падежа к другому.

switch (n)
{
    case 1:
        Console.WriteLine("Case 1");
        break;
    case 2:
        Console.WriteLine("Case 2");
        goto case 1;
    case 3:
        Console.WriteLine("Case 3");
    case 4: // Compilation will fail here as cases cannot fall through in C#.
        Console.WriteLine("Case 4");
        goto default; // This is the correct way to fall through to the next case.
    case 5:  // Multiple labels for the same code are OK
    case 6:
    default:
        Console.WriteLine("Default");
        break;  // Even default must not reach the end point
}

break заявление

[ редактировать ]

The break оператор выходит из ближайшего цикла или switch заявление. Выполнение продолжается в операторе после прерванного оператора, если таковой имеется.

int e = 10;
for (int i = 0; i < e; i++)
{
    while (true)
    {
        break;
    }
    // Will break to this point.
}

continue заявление

[ редактировать ]

The continue Оператор прекращает текущую итерацию текущего оператора управления и начинает следующую итерацию.

int ch;
while ((ch = Console.Read()) != -1)
{
   	if (ch == ' ')
      		continue;    // Skips the rest of the while-loop

   	// Rest of the while-loop
   	...
}

The while цикл в приведенном выше коде читает символы, вызывая GetChar(), пропуская операторы в теле цикла, если символы являются пробелами.

Обработка исключений

[ редактировать ]

Метод обработки исключений во время выполнения в C# унаследован от Java и C++.

В библиотеке базовых классов есть класс под названием System.Exception из которого получены все остальные классы исключений. Ан Exception-object содержит всю информацию о конкретном исключении, а также о вызванных внутренних исключениях. Программисты могут определять свои собственные исключения, исходя из Exception сорт.

Исключение можно создать следующим образом:

throw new NotImplementedException();

try ... catch ... finally заявления

[ редактировать ]

Исключения управляются внутри try ... catch блоки.

try
{
    // Statements which may throw exceptions
    ...
}
catch (Exception ex)
{
    // Exception caught and handled here
    ...
}
finally
{
    // Statements always executed after the try/catch blocks
    ...
}

Заявления в рамках try блок выполняются, и если какой-либо из них генерирует исключение, выполнение блока прекращается, и исключение обрабатывается catch блокировать. Может быть несколько catch блоков, в этом случае выполняется первый блок с переменной исключения, тип которой соответствует типу выброшенного исключения.

Если нет catch соответствует типу выброшенного исключения, выполнение внешнего блока (или метода), содержащего try ... catch оператор прекращается, и исключение передается за пределы содержащего его блока или метода. Исключение распространяется вверх по стеку вызовов до тех пор, пока не будет найдено соответствующее исключение. catch блок находится в одном из активных в данный момент методов. Если исключение распространяется до самого верхнего Main() метод без сопоставления catch При обнаружении блока вся программа завершается, а текстовое описание исключения записывается в стандартный поток вывода.

Заявления в рамках finally блок всегда выполняется после try и catch блоков, независимо от того, было ли выдано исключение. Такие блоки полезны для предоставления кода очистки.

Либо catch блок, а finally блок или оба должны следовать try блокировать.

C# — это статически типизированный язык, подобный C и C++. Это означает, что каждая переменная и константа при объявлении получает фиксированный тип. Существует два типа типов: типы значений и ссылочные типы .

Типы значений

[ редактировать ]

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

Структуры

[ редактировать ]

Структуры более известны как structs . Структуры — это определяемые пользователем типы значений, которые объявляются с помощью struct ключевое слово. Они очень похожи на классы, но больше подходят для легковесных типов. Некоторые важные синтаксические различия между классом и структурой представлены далее в этой статье .

struct Foo
{
    ...
}

Все примитивные типы данных являются структурами.

Предопределенные типы
[ редактировать ]

Это примитивные типы данных.

Примитивные типы
Введите имя BCL эквивалент Ценить Диапазон Размер Значение по умолчанию
sbyte System.SByte целое число от −128 до +127 8-битный (1-байтовый) 0
short System.Int16 целое число от −32 768 до +32 767 16 бит (2 байта) 0
int System.Int32 целое число от −2 147 483 648 до +2 147 483 647 32-битный (4-байтовый) 0
long System.Int64 целое число −9 223 372 036 854 775 808 через
+9,223,372,036,854,775,807
64-битный (8-байтовый) 0
byte System.Byte целое число без знака от 0 до 255 8-битный (1-байтовый) 0
ushort System.UInt16 целое число без знака от 0 до 65 535 16 бит (2 байта) 0
uint System.UInt32 целое число без знака от 0 до 4 294 967 295 32-битный (4-байтовый) 0
ulong System.UInt64 целое число без знака от 0 до 18 446 744 073 709 551 615 64-битный (8-байтовый) 0
decimal System.Decimal десятичное число со знаком −79 228 162 514 264 337 593 543 950 335 через
+79,228,162,514,264,337,593,543,950,335
128-битный (16-байтовый) 0.0
float System.Single число с плавающей запятой от ±1,401298E−45 до ±3,402823E+38 32-битный (4-байтовый) 0.0
double System.Double число с плавающей запятой ±4,94065645841246E-324 через
±1,79769313486232E+308
64-битный (8-байтовый) 0.0
bool System.Boolean логическое значение true или false 8-битный (1-байтовый) false
char System.Char один символ Юникода '\u0000' через '\uFFFF' 16 бит (2 байта) '\u0000'

Примечание: string ( System.String) не является структурой и не является примитивным типом.

Перечисления

[ редактировать ]

Перечислимые типы (объявленные с помощью enum) — это именованные значения, представляющие целочисленные значения.

enum Season
{
    Winter = 0,
    Spring = 1,
    Summer = 2,
    Autumn = 3,
    Fall = Autumn    // Autumn is called Fall in American English.
}

Переменные Enum по умолчанию инициализируются нулем. Им можно назначить или инициализировать именованные значения, определенные типом перечисления.

Season season;
season = Season.Spring;

Переменные типа Enum представляют собой целочисленные значения. Сложение и вычитание между переменными одного типа допускается без какого-либо специального приведения, но умножение и деление несколько более рискованно и требует явного приведения. Приведения также необходимы для преобразования перечисляемых переменных в целочисленные типы и обратно. Однако приведение не выдаст исключение, если значение не указано в определении типа.

season = (Season)2;  // cast 2 to an enum-value of type Season.
season = season + 1; // Adds 1 to the value.
season = season + season2; // Adding the values of two enum variables.
int value = (int)season; // Casting enum-value to integer value.

season++; // Season.Spring (1) becomes Season.Summer (2).
season--; // Season.Summer (2) becomes Season.Spring (1).

Значения можно объединять с помощью побитового оператора ИЛИ. |.

Color myColors = Color.Green | Color.Yellow | Color.Blue;

Типы ссылок

[ редактировать ]

Переменные, созданные для ссылочных типов, являются типизированными управляемыми ссылками. При вызове конструктора в куче создается объект и переменной присваивается ссылка. Когда переменная объекта выходит за пределы области видимости, ссылка разрывается, а когда ссылок не остается, объект помечается как мусор. Сборщик мусора вскоре соберет и уничтожит его.

Ссылочная переменная имеет значение null, если она не ссылается ни на один объект.

Тип массива — это ссылочный тип, который ссылается на пространство, содержащее один или несколько элементов определенного типа. Все типы массивов происходят от общего базового класса, System.Array. На каждый элемент ссылается его индекс, как в C++ и Java.

Массив в C# — это то, что в C++ называется динамическим массивом .

int[] numbers = new int[2];
numbers[0] = 2;
numbers[1] = 5;
int x = numbers[0];
Инициализаторы
[ редактировать ]

Инициализаторы массивов предоставляют удобный синтаксис для инициализации массивов.

// Long syntax
int[] numbers = new int[5]{ 20, 1, 42, 15, 34 };
// Short syntax
int[] numbers2 = { 20, 1, 42, 15, 34 };
// Inferred syntax
var numbers3 = new[] { 20, 1, 42, 15, 34 };
Многомерные массивы
[ редактировать ]

Массивы могут иметь более одного измерения, например два измерения для представления сетки.

int[,] numbers = new int[3, 3];
numbers[1,2] = 2;

int[,] numbers2 = new int[3, 3] { {2, 3, 2}, {1, 2, 6}, {2, 4, 5} };

См. также

Классы — это определяемые пользователем ссылочные типы с самоописанием. По сути, все типы в .NET Framework являются классами, включая структуры и перечисления, которые являются классами, создаваемыми компилятором. Члены класса private по умолчанию, но может быть объявлен как public быть видимым за пределами класса или protected быть видимым любым потомкам класса.

The System.String класс или просто string, представляет собой неизменяемую последовательность символов Юникода ( char).

Действия, выполняемые над строкой, всегда возвращают новую строку.

string text = "Hello World!";
string substr = text.Substring(0, 5);
string[] parts = text.Split(new char[]{ ' ' });

The System.StringBuilder Класс можно использовать, когда требуется изменяемая «строка».

var sb = new StringBuilder();
sb.Append('H');
sb.Append("el");
sb.AppendLine("lo!");

Интерфейс

[ редактировать ]

Интерфейсы — это структуры данных, которые содержат определения членов без фактической реализации. Переменная типа интерфейса — это ссылка на экземпляр класса, реализующего этот интерфейс. См. #Интерфейсы .

Делегаты

[ редактировать ]

C# предоставляет типобезопасные указатели на объектно-ориентированные функции в форме делегатов .

class Program
{
    // Delegate type:
    delegate int Operation(int a, int b);

    static int Add(int i1, int i2)
    {
        return i1 + i2;
    }

    static int Sub(int i1, int i2)
    {
        return i1 - i2;
    }

    static void Main()
    {
        // Instantiate the delegate and assign the method to it.
        Operation op = Add;

        // Call the method that the delegate points to.
        int result1 = op(2, 3);  // 5

        op = Sub;
        int result2 = op(10, 2); // 8
    }
}

Инициализация делегата анонимным методом.

addition = delegate(int a, int b) { return a + b; };

Инициализация делегата с помощью лямбда-выражения.

addition = (a, b) => a + b;

События — это указатели , которые могут указывать на несколько методов. Точнее, они привязывают указатели методов к одному идентификатору. Поэтому это можно рассматривать как расширение делегатов . Обычно они используются в качестве триггеров при разработке пользовательского интерфейса. Форма, используемая в C# и остальной части Common Language Infrastructure , основана на форме в классическом Visual Basic .

delegate void MouseEventHandler(object sender, MouseEventArgs e);

public class Button : System.Windows.Controls.Control
{
    private event MouseEventHandler _onClick;

    /* Imaginary trigger function */
    void Click()
    {
        _onClick(this, new MouseEventArgs(data));
    }
}

Для события требуется сопровождаемый обработчик событий , созданный на основе специального делегата, который в библиотеке, специфичной для платформы, такой как Windows Presentation Foundation и Windows Forms, обычно принимает два параметра: отправителя и аргументы события . Тип объекта аргумента события наследуется от класса EventArgs, который является частью базовой библиотеки CLI.

После объявления в своем классе единственный способ вызвать событие — изнутри владельца. Метод прослушивателя может быть реализован снаружи, чтобы запускаться при возникновении события.

public class MainWindow : System.Windows.Controls.Window
{
    private Button _button1;

    public MainWindow()
    {
        _button1 = new Button();
        _button1.Text = "Click me!";

        /* Subscribe to the event */
        _button1.ClickEvent += Button1_OnClick;

        /* Alternate syntax that is considered old:
        _button1.MouseClick += new MouseEventHandler(Button1_OnClick); */
    }

    protected void Button1_OnClick(object sender, MouseEventArgs e)
    {
        MessageBox.Show("Clicked!");
    }
}

Также возможна реализация пользовательского события:

	private EventHandler _clickHandles = (s, e) => { };

	public event EventHandler Click
	{
		add
		{
			// Some code to run when handler is added...
			...

			_clickHandles += value;
		}
		remove
		{
			// Some code to run when handler is removed...
			...

			_clickHandles -= value;
		}
	}

См. также

Обнуляемые типы

[ редактировать ]
Это особенность C# 2.0 .

Типы, допускающие значение NULL, были введены в C# 2.0 сначала для того, чтобы типы значений могли иметь значение NULL (полезно при работе с базой данных).

int? n = 2;
n = null;

Console.WriteLine(n.HasValue);

На самом деле это то же самое, что использовать Nullable<T> структура.

Nullable<int> n = 2;
n = null;

Console.WriteLine(n.HasValue);

Указатели

[ редактировать ]

В C# есть и разрешены указатели на выбранные типы (некоторые примитивы, перечисления, строки, указатели и даже массивы и структуры, если они содержат только типы, на которые можно указать). [6] ) в небезопасном контексте: отмечены методы и кодовый блок unsafe. Синтаксически они аналогичны указателям в C и C++. Однако проверка времени выполнения отключена внутри unsafe блоки.

static void Main(string[] args)
{
    unsafe
    {
        int a = 2;
        int* b = &a;

        Console.WriteLine("Address of a: {0}. Value: {1}", (int)&a, a);
        Console.WriteLine("Address of b: {0}. Value: {1}. Value of *b: {2}", (int)&b, (int)b, *b);

        // Will output something like:
        // Address of a: 71953600. Value: 2
        // Address of b: 71953596. Value: 71953600. Value of *b: 2
    }
}

Структуры должны быть только чистыми структурами без членов управляемого ссылочного типа, например строки или любого другого класса.

public struct MyStruct
{
    public char Character;
    public int Integer;
}

public struct MyContainerStruct
{
    public byte Byte;
    public MyStruct MyStruct;
}

В использовании:

MyContainerStruct x;
MyContainerStruct* ptr = &x;

byte value = ptr->Byte;

Динамический

[ редактировать ]
Это особенность C# 4.0 и .NET Framework 4.0 .

Тип dynamic — это функция, которая обеспечивает статический динамический поиск C# во время выполнения. Динамический обозначает переменную с объектом, тип которого разрешается во время выполнения, а не во время компиляции, как это обычно делается.

Эта функция использует преимущества среды выполнения динамического языка (DLR) и была разработана специально с целью взаимодействия с динамически типизированными языками , такими как IronPython и IronRuby (реализации Python и Ruby для .NET).

Динамическая поддержка также упрощает взаимодействие с COM- объектами.

dynamic x = new Foo();
x.DoSomething();  // Will compile and resolved at runtime. An exception will be thrown if invalid.

Анонимные типы

[ редактировать ]
Это особенность C# 3.0 .

Анонимные типы — это безымянные классы, создаваемые компилятором. Они являются лишь расходными материалами, но очень полезны в сценарии, например, когда у вас есть запрос LINQ, который возвращает объект. select и вы просто хотите вернуть некоторые конкретные значения. Затем вы можете определить анонимный тип, содержащий автоматически создаваемые поля только для чтения для значений.

При создании экземпляра другого объявления анонимного типа с той же сигнатурой тип автоматически определяется компилятором.

var carl = new { Name = "Carl", Age = 35 }; // Name of the type is only known by the compiler.
var mary = new { Name = "Mary", Age = 22 }; // Same type as the expression above

Упаковка и распаковка

[ редактировать ]

Упаковка — это операция преобразования значения типа значения в значение соответствующего ссылочного типа. [7] Упаковка в C# является неявной.

Распаковка — это операция преобразования значения ссылочного типа (ранее упакованного) в значение типа значения. [7] Распаковка в C# требует явного приведения типа.

Пример:

int foo = 42;         // Value type.
object bar = foo;     // foo is boxed to bar.
int foo2 = (int)bar;  // Unboxed back to value type.

Объектно-ориентированное программирование (ООП)

[ редактировать ]

C# имеет прямую поддержку объектно-ориентированного программирования .

Объект создается с типом в качестве шаблона и называется экземпляром этого конкретного типа.

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

Класс объекта

[ редактировать ]

Все типы, даже типы значений в коробочной форме, неявно наследуются от System.Object class, основной базовый класс всех объектов. Этот класс содержит наиболее распространенные методы, общие для всех объектов. Некоторые из них virtual и может быть переопределено.

Классы наследуют System.Object прямо или косвенно через другой базовый класс.

Члены
Некоторые члены класса Object:

  • Equals - Поддерживает сравнения между объектами.
  • Finalize - Выполняет операции очистки перед автоматическим восстановлением объекта. (деструктор по умолчанию)
  • GetHashCode — Получает число, соответствующее значению объекта, для поддержки использования хеш-таблицы.
  • GetType — Получает тип текущего экземпляра.
  • ToString — Создает удобочитаемую текстовую строку, описывающую экземпляр класса. Обычно он возвращает имя типа.

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

Различия между классами и структурами

[ редактировать ]

Хотя классы и структуры схожи как по способу объявления, так и по способу использования, между ними имеются некоторые существенные различия. Классы являются ссылочными типами, а структуры — типами значений. Структура выделяется в стеке при ее объявлении, а переменная привязывается к ее адресу. Он непосредственно содержит значение. Классы отличаются тем, что память выделяется как объекты в куче. Переменные — это скорее управляемые указатели в стеке, которые указывают на объекты. Это ссылки.

Структуры отличаются от классов еще в нескольких отношениях. Например, хотя оба предлагают неявный конструктор по умолчанию , не принимающий аргументов, вы не можете переопределить его для структур. Явное определение конструктора с другими параметрами приведет к подавлению неявного конструктора по умолчанию в классах, но не в структурах. Все поля структуры должны быть инициализированы в конструкторах такого типа. Структуры не имеют финализаторов и не могут наследовать от другого класса, как это делают классы. Неявно они запечатаны и наследуются от System.ValueType (который наследуется от System.Object). Структуры больше подходят для небольших объемов данных.

Вот краткий обзор различий:

Конструктор по умолчанию Финализатор Инициализация члена Наследование
Классы не требуется (генерируется автоматически) [а] да не требуется да (если базовый класс не sealed)
Структуры требуется (создается автоматически) [б] нет необходимый не поддерживается
  1. ^ Генерируется только в том случае, если не указан другой конструктор.
  2. ^ Всегда генерируется автоматически и не может быть написан программистом.

Декларация

[ редактировать ]

Класс объявляется следующим образом:

class Foo
{
    // Member declarations
}
Частичный класс
[ редактировать ]
Это особенность C# 2.0 .

Частичный класс — это объявление класса, код которого разделен на отдельные файлы. Различные части разделяемого класса должны быть отмечены ключевым словом partial.

// File1.cs
partial class Foo
{
    ...
}

// File2.cs
partial class Foo
{
    ...
}

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

Инициализация

[ редактировать ]

Прежде чем вы сможете использовать члены класса, вам необходимо инициализировать переменную ссылкой на объект. Чтобы создать его, вы вызываете соответствующий конструктор, используя метод new ключевое слово. Он имеет то же имя, что и класс.

var foo = new Foo();

Для структур необязательно явно вызывать конструктор, поскольку конструктор по умолчанию вызывается автоматически. Вам просто нужно объявить его, и он инициализируется стандартными значениями.

Инициализаторы объектов
[ редактировать ]
Это особенность C# 3.0 .

Предоставляет более удобный способ инициализации общедоступных полей и свойств объекта. Вызовы конструктора не являются обязательными, если существует конструктор по умолчанию.

var person = new Person
{
    Name = "John Doe",
    Age = 39
};

// Equal to
var person = new Person();
person.Name = "John Doe";
person.Age = 39;
Инициализаторы коллекций
[ редактировать ]
Это особенность C# 3.0 .

Инициализаторы коллекций предоставляют синтаксис, подобный массиву, для инициализации коллекций. Компилятор просто сгенерирует вызовы метода Add. Это работает для классов, реализующих интерфейс ICollection.

var list = new List<int> {2, 5, 6, 6};

// Equal to
var list = new List<int>();
list.Add(2);
list.Add(5);
list.Add(6);
list.Add(6);

Доступ к участникам

[ редактировать ]

Доступ к членам экземпляра и статическим членам класса осуществляется с помощью . оператор.

Доступ к члену экземпляра
Доступ к членам экземпляра можно получить через имя переменной.

string foo = "Hello";
string fooUpper = foo.ToUpper();

Доступ к статическому члену класса
Доступ к статическим членам осуществляется с использованием имени класса или другого типа.

int r = string.Compare(foo, fooUpper);

Доступ к члену через указатель
В небезопасном коде доступ к членам значения (типа структуры), на который ссылается указатель, осуществляется с помощью -> оператор, как в C и C++.

POINT p;
p.X = 2;
p.Y = 6;
POINT* ptr = &p;
ptr->Y = 4;

Модификаторы

[ редактировать ]

Модификаторы — это ключевые слова, используемые для изменения объявлений типов и членов типов. В частности, существует подгруппа, содержащая модификаторы доступа.

Модификаторы класса
[ редактировать ]
  • abstract — Указывает, что класс служит только базовым классом. Он должен быть реализован в наследующем классе. Предварительное условие, позволяющее классу иметь абстрактные методы.
  • sealed — Указывает, что класс не может быть унаследован.
Модификаторы членов класса
[ редактировать ]
  • abstract — Объявляет метод, доступный во всех производных неабстрактных классах.
  • const — Указывает, что переменная является постоянным значением, которое необходимо инициализировать при объявлении.
  • event - Объявляет событие.
  • extern — Указывает, что сигнатура метода без тела использует импорт DLL.
  • override — Указывает, что объявление метода или свойства является переопределением виртуального члена или реализацией члена абстрактного класса.
  • readonly — Объявляет поле, которому могут быть присвоены значения только как часть объявления или в конструкторе того же класса.
  • unsafe — Указывает небезопасный контекст, который позволяет использовать указатели.
  • virtual — Указывает, что объявление метода или свойства может быть переопределено производным классом.
  • volatile - Указывает поле, которое может быть изменено внешним процессом, и не позволяет оптимизирующему компилятору делать предположения о постоянстве текущего значения поля.
static модификатор
[ редактировать ]

The static Модификатор указывает, что член принадлежит классу, а не конкретному объекту. Классы, помеченные как статические, могут содержать только статические члены. Статические члены иногда называются членами класса, поскольку они применяются к классу в целом, а не к его экземплярам.

public class Foo
{
    public static void Something()
    {
        ...
    }
}
// Calling the class method.
Foo.Something();
Модификаторы доступа
[ редактировать ]

Модификаторы доступа или модификаторы наследования задают доступность классов, методов и других членов. Что-то отмечено public можно добраться откуда угодно. private Доступ к членам возможен только изнутри класса, в котором они объявлены, и они будут скрыты при наследовании. Члены с protected модификатор будет private, но доступен при наследовании. internal классы и члены будут доступны только изнутри объявляющей сборки.

Классы и структуры неявно internal и члены неявно private если у них нет модификатора доступа.

public class Foo
{
    public int Do()
    {
        return 0;
    }

    public class Bar
    {

    }
}

Эта таблица определяет, где можно использовать модификаторы доступа.

Невложенные типы Члены (включая вложенные типы) Доступен для
public да да все
protected internal нет да тот же класс, производные классы и все в одной сборке
protected нет да тот же класс и производные классы
internal да (по умолчанию) да все в одной сборке
private protected нет да тот же класс и производные классы в одной сборке
private нет да (по умолчанию) тот же класс

Конструкторы

[ редактировать ]

Конструктор — это специальный метод, который вызывается автоматически при создании объекта. Его цель — инициализировать члены объекта. Конструкторы имеют то же имя, что и класс, и явно ничего не возвращают. Неявно они вернут вновь созданный объект при вызове через метод new оператор. Они могут принимать параметры, как и любой другой метод. Конструктор без параметров является особенным, поскольку его можно указать как необходимое ограничение для параметра универсального типа.

class Foo
{
    Foo()
    {
        ...
    }
}

Конструкторы могут быть public, private, protected или internal.

Деструктор

[ редактировать ]

Деструктор вызывается , когда объект собирается сборщиком мусора для выполнения некоторой очистки вручную. Существует метод деструктора по умолчанию, называемый finalize это можно переопределить, объявив свой собственный.

Синтаксис аналогичен синтаксису конструкторов. Разница в том, что имени предшествует ~ и оно не может содержать никаких параметров. Не может быть более одного деструктора.

class Foo
{
    ...

    ~Foo()
    {
        ...
    }
}

Финализаторы всегда private.

Как и в C и C++, существуют функции, группирующие повторно используемый код. Основное отличие состоит в том, что функции, как и в Java, должны находиться внутри класса. Поэтому функция называется методом . Метод имеет возвращаемое значение, имя и обычно некоторые параметры, инициализируемые при его вызове с некоторыми аргументами. Он может либо принадлежать экземпляру класса, либо быть статическим членом.

class Foo
{
    int Bar(int a, int b)
    {
        return a%b;
    }
}

Метод помощью вызывается с . обозначение конкретной переменной или, как в случае со статическими методами, имя типа.

Foo foo = new Foo();
int r = foo.Bar(7, 2);

Console.WriteLine(r);
ref и out параметры
[ редактировать ]

Можно явно указать, что аргументы передаются по ссылке при вызове метода с параметрами, которым предшествуют ключевые слова. ref или out. Эти управляемые указатели пригодятся при передаче переменных, которые вы хотите изменить, внутри метода по ссылке. Основное различие между ними заключается в том, что out параметр должен быть назначен внутри метода к моменту возврата метода. ref может присвоить или не присвоить новое значение, но переменная параметра должна быть инициализирована перед вызовом функции.

void PassRef(ref int x)
{
    if (x == 2)
        x = 10;
}
int Z = 7;
PassRef(ref Z);

void PassOut(out int x)
{
    x = 2;
}
int Q;
PassOut(out Q);
Дополнительные параметры
[ редактировать ]
Это особенность C# 4.0 .

В C# 4.0 представлены необязательные параметры со значениями по умолчанию, как в C++. Например:

void Increment(ref int x, int dx = 1)
{
    x += dx;
}

int x = 0;
Increment(ref x);    // dx takes the default value of 1
Increment(ref x, 2); // dx takes the value 2

Кроме того, в дополнение к необязательным параметрам можно явно указывать имена параметров в вызовах методов, что позволяет выборочно передавать в метод любое заданное подмножество необязательных параметров. Единственное ограничение состоит в том, что именованные параметры должны располагаться после неименованных параметров. Имена параметров могут быть указаны как для необязательных, так и для обязательных параметров и могут использоваться для улучшения читаемости или произвольного изменения порядка аргументов в вызове. Например:

Stream OpenFile(string name, FileMode mode = FileMode.Open,
FileAccess access = FileAccess.Read) { ... }

OpenFile("file.txt"); // use default values for both "mode" and "access"
OpenFile("file.txt", mode: FileMode.Create); // use default value for "access"
OpenFile("file.txt", access: FileAccess.Read); // use default value for "mode"
OpenFile(name: "file.txt", access: FileAccess.Read, mode: FileMode.Create);
// name all parameters for extra readability,
// and use order different from method declaration

Дополнительные параметры упрощают взаимодействие с COM. Раньше C# приходилось передавать каждый параметр в метод компонента COM, даже те, которые не являются обязательными. Например:

object fileName = "Test.docx";
object missing = System.Reflection.Missing.Value;

doc.SaveAs(ref fileName,
    ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing);
console.writeline("File saved successfully");

Благодаря поддержке необязательных параметров код можно сократить до

doc.SaveAs(ref fileName);

Особенностью C# является возможность вызова машинного кода. Сигнатура метода просто объявляется без тела и помечается как extern. DllImport Также необходимо добавить атрибут для ссылки на нужный файл DLL.

[DllImport("win32.dll")]
static extern double Pow(double a, double b);

Поля или переменные экземпляра могут быть объявлены внутри тела класса для хранения данных.

class Foo
{
    double foo;
}

Поля могут быть инициализированы непосредственно при объявлении (если они не объявлены в структуре).

class Foo
{
    double foo = 2.3;
}

Модификаторы полей:

  • const - Делает поле постоянным.
  • private - Делает поле приватным (по умолчанию).
  • protected - Делает поле защищенным.
  • public - Делает поле общедоступным.
  • readonly — Позволяет инициализировать поле только один раз в конструкторе.
  • static — Делает поле статическим членом, т.е. переменной класса .

Характеристики

[ редактировать ]

Свойства содержат синтаксис, подобный полю, и сочетают его с мощью методов. Свойство может иметь два метода доступа: get и set.

public class Person
{
    private string _name;

    string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

// Using a property
var person = new Person();
person.Name = "Robert";

Модификаторы свойств:

  • private - Делает собственность частной (по умолчанию).
  • protected - Делает собственность защищенной.
  • public - Делает собственность публичной.
  • static — Делает свойство статическим членом.

Модификаторы для средств доступа к свойствам:

  • private - Делает метод доступа закрытым.
  • protected - Делает аксессор защищенным.
  • public - Делает аксессор общедоступным.

Модификаторы по умолчанию для средств доступа наследуются от свойства. Обратите внимание, что модификаторы средства доступа могут быть равны или более строги, чем модификатор свойства.

Автоматические свойства
[ редактировать ]
Это особенность C# 3.0 .

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

public double Width { get; private set; }

Индексаторы

[ редактировать ]

Индексаторы добавляют к объектам возможности индексирования, подобные массивам. Они реализованы аналогично свойствам.

internal class IntList
{
    private int[] _items;

    int this[int index]
    {
        get { return _items[index]; }
        set { _items[index] = value; }
    }
}

// Using an indexer
var list = new IntList();
list[2] = 2;

Наследование

[ редактировать ]

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

class A
{
}


class B : A
{

}

Методы отмечены virtual предоставляют реализацию, но они могут быть переопределены наследниками с помощью override ключевое слово.

Реализация выбирается по фактическому типу объекта, а не по типу переменной.

class Operation
{
    public virtual int Do()
    {
        return 0;
    }
}

class NewOperation : Operation
{
    public override int Do()
    {
        return 1;
    }
}

При перегрузке невиртуального метода другой сигнатурой ключевое слово new можно использовать. Используемый метод будет выбран по типу переменной, а не по фактическому типу объекта.

class Operation
{
    public int Do()
    {
        return 0;
    }
}

class NewOperation : Operation
{
    public new double Do()
    {
        return 4.0;
    }
}

Это демонстрирует случай:

var operation = new NewOperation();

// Will call "double Do()" in NewOperation
double d = operation.Do();

Operation operation_ = operation;

// Will call "int Do()" in Operation
int i = operation_.Do();

Абстрактные классы — это классы, которые служат только шаблонами, и вы не можете инициализировать объект этого типа. В остальном это как обычный класс.

Могут быть и абстрактные члены. Абстрактные члены — это члены абстрактных классов, не имеющие никакой реализации. Они должны быть переопределены любым неабстрактным классом, наследующим этот член.

abstract class Mammal
{
    public abstract void Walk();
}

class Human : Mammal
{
    public override void Walk()
    {

    }

    ...
}

The sealed модификатор можно комбинировать с другими в качестве дополнительного модификатора классов, чтобы сделать их ненаследуемыми, или для методов, запрещающих их переопределение в производных классах.

internal sealed class Foo
{
    //...
}

public class Bar
{
    public virtual void Action()
    {
        //...
    }
}

public class Baz : Bar
{
    public sealed override void Action()
    {
        //...
    }
}

Интерфейсы

[ редактировать ]

Интерфейсы — это структуры данных, которые содержат определения членов, а не фактическую реализацию. Они полезны, когда вы хотите определить контракт между членами разных типов, которые имеют разные реализации. Вы можете объявить определения методов, свойств и индексаторов. Члены интерфейса неявно общедоступны. Интерфейс может быть реализован неявно или явно.

interface IBinaryOperation
{
    double A { get; set; }
    double B { get; set; }

    double GetResult();
}

Реализация интерфейса

[ редактировать ]

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

Неявная реализация

При неявной реализации интерфейса члены интерфейса должны быть public.

public class Adder : IBinaryOperation
{
    public double A { get; set; }
    public double B { get; set; }

    public double GetResult()
    {
        return A + B;
    }
}

public class Multiplier : IBinaryOperation
{
    public double A { get; set; }
    public double B { get; set; }

    public double GetResult()
    {
        return A * B;
    }
}

В использовании:

IBinaryOperation op = null;
double result;

// Adder implements the interface IBinaryOperation.

op = new Adder();
op.A = 2;
op.B = 3;

result = op.GetResult(); // 5

// Multiplier also implements the interface.

op = new Multiplier();
op.A = 5;
op.B = 4;

result = op.GetResult(); // 20

Явная реализация

Вы также можете явно реализовать члены. Члены интерфейса, явно реализованные классом, доступны только тогда, когда объект обрабатывается как тип интерфейса.

public class Adder : IBinaryOperation
{
    double IBinaryOperation.A { get; set; }
    double IBinaryOperation.B { get; set; }

    double IBinaryOperation.GetResult()
    {
        return ((IBinaryOperation)this).A + ((IBinaryOperation)this).B;
    }
}

В использовании:

Adder add = new Adder();

// These members are not accessible:
// add.A = 2;
// add.B = 3;
// double result = add.GetResult();

// Cast to the interface type to access them:
IBinaryOperation add2 = add;
add2.A = 2;
add2.B = 3;

double result = add2.GetResult();

Примечание. Свойства класса, расширяющего IBinaryOperation автоматически реализуются компилятором, и автоматически добавляется резервное поле (см. #Автоматические свойства ).

Расширение нескольких интерфейсов

Интерфейсам и классам разрешено расширять несколько интерфейсов.

class MyClass : IInterfaceA, IInterfaceB
{
    ...
}

Вот интерфейс, который расширяет два интерфейса.

interface IInterfaceC : IInterfaceA, IInterfaceB
{
    ...
}

Интерфейсы против абстрактных классов

[ редактировать ]

Интерфейсы и абстрактные классы похожи. Ниже описаны некоторые важные различия:

  • Абстрактный класс может иметь переменные-члены, а также неабстрактные методы или свойства. Интерфейс не может.
  • Класс или абстрактный класс может наследовать только от одного класса или абстрактного класса.
  • Класс или абстрактный класс может реализовывать один или несколько интерфейсов.
  • Интерфейс может только расширять другие интерфейсы.
  • Абстрактный класс может иметь закрытые методы и свойства (в том числе абстрактные). Интерфейс может иметь только открытые члены.
  • Абстрактный класс может иметь константы, статические методы и статические члены. Интерфейс не может.
  • Абстрактный класс может иметь конструкторы. Интерфейс не может.

Дженерики

[ редактировать ]
Это особенность C# 2.0 и .NET Framework 2.0 .

Обобщенные типы (или параметризованные типы, параметрический полиморфизм ) используют параметры типа, которые позволяют разрабатывать классы и методы, которые не указывают используемый тип до тех пор, пока не будет создан экземпляр класса или метода. Основное преимущество заключается в том, что можно использовать параметры универсального типа для создания классов и методов, которые можно использовать без затрат на приведение типов или операции упаковки во время выполнения, как показано здесь: [8]

// Declare the generic class.

public class GenericList<T>
{
    void Add(T input) { }
}

class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        // Declare a list of type int.
        var list1 = new GenericList<int>();

        // Declare a list of type string.
        var list2 = new GenericList<string>();

        // Declare a list of type ExampleClass.
        var list3 = new GenericList<ExampleClass>();
    }
}

По сравнению с шаблонами C++ универсальные шаблоны C# могут обеспечить повышенную безопасность, но при этом имеют несколько ограниченные возможности. [9] Например, невозможно вызывать арифметические операторы для универсального типа C#. [10] В отличие от шаблонов C++, параметризованные типы .NET создаются во время выполнения, а не компилятором; следовательно, они могут быть межъязыковыми, тогда как шаблоны C++ не могут. Они поддерживают некоторые функции, не поддерживаемые напрямую шаблонами C++, такие как ограничения типа для универсальных параметров с помощью интерфейсов. С другой стороны, C# не поддерживает универсальные параметры, не относящиеся к типам.

В отличие от дженериков в Java, дженерики .NET используют реификацию , чтобы сделать параметризованные типы первоклассными объектами в виртуальной машине Common Language Infrastructure (CLI), что позволяет оптимизировать и сохранять информацию о типах. [11]

Использование дженериков

[ редактировать ]

Общие классы

[ редактировать ]

Классы и структуры могут быть универсальными.

public class List<T>
{
    ...
    public void Add(T item)
    {
         ...
    }
}

var list = new List<int>();
list.Add(6);
list.Add(2);

Общие интерфейсы

[ редактировать ]
interface IEnumerable<T>
{
    ...
}

Общие делегаты

[ редактировать ]
delegate R Func<T1, T2, R>(T1 a1, T2 a2);

Общие методы

[ редактировать ]
public static T[] CombineArrays<T>(T[] a, T[] b)
{
    T[] newArray = new T[a.Length + b.Length];
    a.CopyTo(newArray, 0);
    b.CopyTo(newArray, a.Length);
    return newArray;
}

string[] a = new string[] { "a", "b", "c" };
string[] b = new string[] { "1", "2", "3" };
string[] c = CombineArrays(a, b);

double[] da = new double[] { 1.2, 2.17, 3.141592 };
double[] db = new double[] { 4.44, 5.6, 6.02 };
double[] dc = CombineArrays(da, db);

// c is a string array containing { "a", "b", "c", "1", "2", "3"}
// dc is a double array containing { 1.2, 2.17, 3.141592, 4.44, 5.6, 6.02}

Тип-параметры

[ редактировать ]

Параметры типа — это имена, используемые вместо конкретных типов при определении нового обобщенного типа. Их можно связать с классами или методами, поместив параметр типа в угловые скобки. < >. При создании экземпляра (или вызове) универсального метода вы можете заменить конкретный тип на параметр типа, который вы указали в его объявлении. Параметры типа могут быть ограничены с помощью where ключевое слово и спецификацию ограничения, можно использовать любое из шести ограничений, разделенных запятыми: [12]

Ограничение Объяснение
where T : struct параметр типа должен быть типом значения
where T : class параметр типа должен быть ссылочным типом
where T : new() параметр типа должен иметь конструктор без параметров (должен появляться последним)
where T : <base_class> параметр типа должен наследовать от <base_class>
where T : <interface> параметр типа должен быть или должен реализовывать этот интерфейс
where T : U ограничение параметра голого типа

Ковариантность и контравариантность

[ редактировать ]
Это особенность C# 4.0 и .NET Framework 4.0 .

общих Параметры типов интерфейсов и делегатов могут быть помечены как ковариантные или контравариантные с использованием ключевых слов. out и in, соответственно. Эти объявления затем учитываются при преобразованиях типов, как неявных, так и явных, а также во время компиляции и выполнения. Например, существующий интерфейс IEnumerable<T> было переопределено следующим образом:

interface IEnumerable<out T>
{
    IEnumerator<T> GetEnumerator();
}

Следовательно, любой класс, реализующий IEnumerable<Derived> для какого-то класса Derived также считается совместимым с IEnumerable<Base> для всех классов и интерфейсов Base что Derived распространяется прямо или косвенно. На практике это позволяет писать такой код, как:

void PrintAll(IEnumerable<object> objects)
{
    foreach (object o in objects)
    {
        System.Console.WriteLine(o);
    }
}

IEnumerable<string> strings = new List<string>();
PrintAll(strings); // IEnumerable<string> is implicitly converted to IEnumerable<object>

Для контрвариантности существующий интерфейс IComparer<T> было переопределено следующим образом:

public interface IComparer<in T>
{
    int Compare(T x, T y);
}

Следовательно, любой класс, реализующий IComparer<Base> для какого-то класса Base также считается совместимым с IComparer<Derived> для всех классов и интерфейсов Derived которые простираются от Base. Это позволяет писать такой код, как:

IComparer<object> objectComparer = GetComparer();
IComparer<string> stringComparer = objectComparer;

Счетчики

[ редактировать ]

Перечислитель это итератор. Перечислители обычно получаются путем вызова метода GetEnumerator() метод объекта, реализующий IEnumerable интерфейс. Классы-контейнеры обычно реализуют этот интерфейс. Однако оператор foreach в C# может работать с любым объектом, предоставляющим такой метод, даже если он не реализует IEnumerable. Этот интерфейс был расширен до общей версии в .NET 2.0 .

Ниже показано простое использование итераторов в C# 2.0:

// explicit version
IEnumerator<MyType> iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

// implicit version
foreach (MyType value in list)
    Console.WriteLine(value);

Функциональность генератора

[ редактировать ]
Это особенность C# 2.0 .

Платформа .NET 2.0 Framework позволила C# ввести итератор , обеспечивающий генератора , используя функциональность yield return построить аналогично yield в Питоне . [13] С yield return, функция автоматически сохраняет свое состояние во время итерации.

// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
public static IEnumerable<int> GetEven(IEnumerable<int> numbers)
{
    foreach (int i in numbers)
    {
        if (i%2 == 0)
            yield return i;
    }
}

// using the method to output only even numbers from the array
static void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5, 6};
    foreach (int i in GetEven(numbers))
        Console.WriteLine(i);  //outputs 2, 4 and 6
}
Это особенность C# 3.0 и .NET Framework 3.0 .

LINQ, сокращение от «Language Integrated Queries», — это функция .NET Framework, которая упрощает обработку данных. В основном он добавляет поддержку, позволяющую запрашивать массивы, коллекции и базы данных. Он также вводит связующие, что упрощает доступ к базам данных и их данным.

Синтаксис запроса

[ редактировать ]

Синтаксис запросов LINQ был представлен в C# 3.0 и позволяет писать SQL -подобные запросы на C#.

var list = new List<int>{ 2, 7, 1, 3, 9 };

var result = from i in list
             where i > 1
             select i;

Операторы компилируются в вызовы методов, при этом указываются почти только имена методов. Какие методы в конечном итоге будут использоваться, определяется обычным разрешением перегрузки. Таким образом, на конечный результат перевода влияет то, какие символы входят в область видимости.

Отличие от SQL заключается в том, что оператор from идет первым, а не последним, как в SQL. Это потому, что такое написание на C# кажется более естественным. [ нужна ссылка ] и поддерживает «Intellisense» (дополнение кода в редакторе).

Анонимные методы

[ редактировать ]

Анонимные методы , или в их нынешней форме, чаще называемые «лямбда-выражениями», — это функция, которая позволяет программистам писать в своем коде встроенные функции, подобные замыканию .

Существуют различные способы создания анонимных методов. До C# 3.0 поддержка делегатов была ограничена.

Анонимные делегаты

[ редактировать ]
Это особенность C# 2.0 .

Анонимные делегаты — это указатели на функции, содержащие анонимные методы. Цель состоит в том, чтобы упростить использование делегатов за счет упрощения процесса назначения функции. Вместо объявления отдельного метода в коде программист может использовать синтаксис для написания встроенного кода, а затем компилятор сгенерирует для него анонимную функцию.

Func<int, int> f = delegate(int x) { return x * 2; };

Лямбда-выражения

[ редактировать ]
Это особенность C# 3.0 .

Лямбда-выражения предоставляют простой синтаксис для встроенных функций, похожих на замыкания. Функции с параметрами определяют тип параметров, если другое не указано явно.

// [arguments] => [method-body]

// With parameters
n => n == 2
(a, b) => a + b
(a, b) => { a++; return a + b; }

// With explicitly typed parameters
(int a, int b) => a + b

// No parameters
() => return 0

// Assigning lambda to delegate
Func<int, int, int> f = (a, b) => a + b;

Многовыраженные лямбды имеют тело, заключенное в фигурные скобки, и внутри них можно писать код, как в стандартных методах.

(a, b) => { a++; return a + b; }

Лямбда-выражения можно передавать в качестве аргументов непосредственно при вызове методов, аналогично анонимным делегатам, но с более эстетичным синтаксисом.

var list = stringList.Where(n => n.Length > 2);

Лямбда-выражения — это, по сути, методы, создаваемые компилятором и передаваемые через делегаты. Эти методы зарезервированы только для компилятора и не могут использоваться ни в каком другом контексте.

Методы расширения

[ редактировать ]
Это особенность C# 3.0 .

Методы расширения — это форма синтаксического сахара, создающая иллюзию добавления новых методов к существующему классу за пределами его определения. На практике метод расширения — это статический метод, который можно вызывать, как если бы он был методом экземпляра; получатель вызова привязан к первому параметру метода, украшенному ключевым словом this:

public static class StringExtensions
{
    public static string Left(this string s, int n)
    {
        return s.Substring(0, n);
    }
}

string s = "foo";
s.Left(3); // same as StringExtensions.Left(s, 3);

Локальные функции

[ редактировать ]
Это особенность C# 7.0.

Локальные функции могут быть определены в теле другого метода, конструктора или метода получения и установки свойства. Такие функции имеют доступ ко всем переменным в окружающей области, включая локальные переменные родительского метода. Они находятся в области действия всего метода, независимо от того, вызваны ли они до или после их объявления. Модификаторы доступа (открытый, частный, защищенный) нельзя использовать с локальными функциями. Также они не поддерживают перегрузку функций . Это означает, что в одном методе не может быть двух локальных функций с одинаковым именем, даже если сигнатуры не перекрываются. [14] После компиляции локальная функция преобразуется в частный статический метод, но после определения ее нельзя пометить как статическую. [15]

В примере кода ниже метод Sum является локальной функцией внутри метода Main. Поэтому его можно использовать только внутри родительского метода Main:

static void Main(string[] args)
{
    int Sum(int x, int y)
    {
        return x + y;
    }

    Console.WriteLine(Sum(10, 20));
    Console.ReadKey();
}

Разнообразный

[ редактировать ]

Запорные блоки

[ редактировать ]

реализуются В C# блоки замыкания с помощью using заявление . using оператор принимает выражение, которое приводит к реализации объекта IDisposable, а компилятор генерирует код, гарантирующий удаление объекта, когда область действия using-оператор завершен. using утверждение является синтаксическим сахаром . Это делает код более читабельным, чем его эквивалент. try ... finally блокировать.

public void Foo()
{
    using (var bar = File.Open("Foo.txt"))
    {
        // do some work
        throw new Exception();
        // bar will still get properly disposed.
    }
}

Синхронизация потоков

[ редактировать ]

C# предоставляет lock оператор , который является еще одним примером полезного синтаксического сахара. Он работает, помечая блок кода как критический раздел путем взаимного исключения доступа к предоставленному объекту. Как using оператор, он работает за счет того, что компилятор генерирует try ... finally блок на своем месте.

private static StreamWriter _writer;

public void ConcurrentMethod()
{
    lock (_writer)
    {
        _writer.WriteLine("Line 1.");
        _writer.WriteLine("Followed by line 2.");
    }
}

Атрибуты

[ редактировать ]

Атрибуты — это объекты данных, которые хранятся в виде метаданных в скомпилированной сборке. Атрибут можно добавить к типам и членам, таким как свойства и методы. Атрибуты можно использовать для лучшего обслуживания директив препроцессора.

[CompilerGenerated]
public class $AnonymousType$120
{
    [CompilerGenerated]
    public string Name { get; set; }
}

.NET Framework поставляется с предопределенными атрибутами, которые можно использовать. Некоторые из них играют важную роль во время выполнения, а некоторые предназначены только для синтаксического оформления кода, например CompilerGenerated. Он лишь отмечает, что это элемент, сгенерированный компилятором. Также можно создавать атрибуты, определяемые программистом.

Атрибут — это, по сути, класс, который наследуется от System.Attribute сорт. По соглашению классы атрибутов заканчиваются словом «Атрибут» в своем имени. При использовании этого не потребуется.

public class EdibleAttribute : Attribute
{
    public EdibleAttribute() : base()
    {

    }

    public EdibleAttribute(bool isNotPoisonous)
    {
        this.IsPoisonous = !isNotPoisonous;
    }

    public bool IsPoisonous { get; set; }
}

Показ используемого атрибута с использованием необязательных параметров конструктора.

[Edible(true)]
public class Peach : Fruit
{
   // Members if any
}

Препроцессор

[ редактировать ]

В C# есть «директивы препроцессора». [16] (хотя у него нет настоящего препроцессора), основанный на препроцессоре C , который позволяет программистам определять символы , но не макросы. Условные обозначения, такие как #if, #endif, и #else также предусмотрены.

Такие директивы, как #region давать подсказки редакторам по складыванию кода . #region блок должен заканчиваться #endregion директива.

public class Foo
{
    #region Constructors
    public Foo() {}
    public Foo(int firstParam) {}
    #endregion

    #region Methods
    public void IntBar(int firstParam) {}
    public void StrBar(string firstParam) {}
    public void BoolBar(bool firstParam) {}
    #endregion
}

Комментарии к коду

[ редактировать ]

В C# используется двойная косая черта ( //), чтобы указать, что остальная часть строки является комментарием.

public class Foo
{
    // a comment
    public static void Bar(int firstParam) {}  // Also a comment
}

Многострочные комментарии могут обозначаться начальной косой чертой/звездочкой ( /*) и завершающая звездочка/косая черта ( */).

public class Foo
{
    /* A multi-line
       comment  */
    public static void Bar(int firstParam) {}
}

Комментарии не вложены. Это два одиночных комментария:

// Can put /* */ */ */ /* /*
/* Can put /* /* /* but it ends with */

Для XML-документации используются однострочные комментарии, начинающиеся с трех косых черт. Однако это соглашение, используемое Visual Studio, и не является частью определения языка:

    /// <summary>
    /// This class is very classy.
    /// </summary>

Комментарии к XML-документации

[ редактировать ]

C# к документации Комментарии [17] аналогичны Javadoc Java , но основаны на XML . C# поддерживает два метода документирования В настоящее время компилятор .

Однострочные комментарии к документации, например те, которые обычно встречаются в коде, созданном Visual Studio , указываются в строке, начинающейся с ///.

public class Foo
{
    /// <summary>A summary of the method.</summary>
    /// <param name="firstParam">A description of the parameter.</param>
    /// <remarks>Remarks about the method.</remarks>
    public static void Bar(int firstParam) {}
}

Многострочные комментарии к документации, определенные в спецификации языка версии 1.0, не поддерживались до выпуска .NET 1.1. [18] Эти комментарии обозначаются начальной косой чертой/звездочкой/звездочкой ( /**) и завершающая звездочка/косая черта ( */). [19]

public class Foo
{
    /** <summary>A summary of the method.</summary>
     *  <param name="firstParam">A description of the parameter.</param>
     *  <remarks>Remarks about the method.</remarks> */
    public static void Bar(int firstParam) {}
}

Существуют некоторые строгие критерии в отношении пробелов и XML-документации при использовании косой черты/звездочки/звездочки ( /**) техника.

Этот блок кода:

/**
 * <summary>
 * A summary of the method.</summary>*/

создает комментарий XML, отличный от этого блока кода: [19]

/**
 * <summary>
   A summary of the method.</summary>*/

Синтаксис комментариев к документации и их XML- разметка определены в ненормативном приложении стандарта ECMA C#. Тот же стандарт также определяет правила обработки таких комментариев и их преобразования в простой документ XML с точными правилами сопоставления идентификаторов Common Language Infrastructure (CLI) с соответствующими элементами документации. Это позволяет любой интегрированной среде разработки C# (IDE) или другому инструменту разработки находить документацию для любого символа в коде определенным четко определенным способом.

Синтаксис асинхронного ожидания

[ редактировать ]
Это особенность C# 5.0 и .NET Framework 4.0 .

Начиная с .NET Framework 4 имеется библиотека задач, которая упрощает написание параллельных и многопоточных приложений с помощью задач.

В C# 5.0 имеется поддержка асинхронности на родном языке.

Рассмотрим этот код, который напрямую использует преимущества библиотеки задач:

public static class SomeAsyncCode
{
    public static Task<XDocument> GetContentAsync()
    {
        var httpClient = new HttpClient();
        return httpClient.GetStringAsync("https://www.contoso.com/").ContinueWith((task) => {
            string responseBodyAsText = task.Result;
            return XDocument.Parse(responseBodyAsText);
        });
    }
}

var t = SomeAsyncCode.GetContentAsync().ContinueWith((task) => {
    var xmlDocument = task.Result;
});

t.Start();

Вот та же логика, записанная в синтаксисе async-await :

public static class SomeAsyncCode
{
    public static async Task<XDocument> GetContentAsync()
    {
        var httpClient = new HttpClient();
        string responseBodyAsText = await httpClient.GetStringAsync("https://www.contoso.com/");
        return XDocument.Parse(responseBodyAsText);
    }
}

var xmlDocument = await SomeAsyncCode.GetContentAsync();

// The Task will be started on call with await.

Диалекты

[ редактировать ]

Спецификация#

[ редактировать ]

Spec# — это диалект C#, разрабатываемый параллельно со стандартной реализацией Microsoft. Он расширяет C# функциями языка спецификаций и является возможной будущей функцией языка C#. Он также добавляет синтаксис для API контрактов кода, который был представлен в .NET Framework 4.0 . Spec# разрабатывается Microsoft Research .

В этом примере показаны две базовые структуры, которые используются при добавлении контрактов в код.

static void Main(string![] args)
    requires args.Length > 0
{
    foreach (string arg in args)
    {

    }
}
  • ! используется для того, чтобы сделать ссылочный тип не допускающим значения NULL, например, вы не можете установить значение NULL. Это в отличие от типов, допускающих значение NULL, которые позволяют устанавливать типы значений как NULL.
  • requires указывает условие, которое должно соблюдаться в коде. В этом случае длина аргументов не может быть равна нулю или меньше.

Необнуляемые типы

[ редактировать ]

Spec# расширяет C# типами, допускающими значение NULL, которые просто проверяют, что переменные типов, допускающих значение NULL, которые были установлены как не допускающие NULL, не имеют значения NULL. Если значение равно нулю, будет выдано исключение.

   string! input

В использовании:

public Test(string! input)
{
    ...
}

Предварительные условия

[ редактировать ]

Предварительные условия проверяются перед выполнением метода.

public Test(int i)
    requires i > 0;
{
    this.i = i;
}

Постусловия

[ редактировать ]

Постусловия — это условия, корректность которых гарантируется при выполнении метода.

public void Increment()
    ensures i > 0;
{
    i++;
}

Проверенные исключения

[ редактировать ]

Spec# добавляет проверенные исключения, подобные тем, которые есть в Java .

public void DoSomething()
    throws SomeException; // SomeException : ICheckedException
{
    ...
}

Проверяемые исключения проблематичны, поскольку когда функция нижнего уровня добавляет новый тип исключения, вся цепочка методов, использующих этот метод на каком-то вложенном нижнем уровне, также должна изменить свой контракт. Это нарушает принцип открытости/закрытости . [20]

См. также

[ редактировать ]
  1. ^ «Соглашения о кодировании на C#» . Microsoft Learn . сек. Соглашения об именах. Архивировано из оригинала 16 января 2023 года.
  2. ^ Jump up to: а б Вагнер, Билл. «Ключевые слова C#» . docs.microsoft.com . Проверено 26 августа 2022 г.
  3. ^ Шилдт, Герберт (30 декабря 2008 г.), C# 3.0: Полный справочник , ISBN  9780071588416
  4. ^ Дейтел, Харви М.; Дейтел, Пол Дж. (21 ноября 2005 г.), C # для программистов , ISBN  9780132465915
  5. ^ Вагнер, Билл. «Ключевые слова C#» . docs.microsoft.com . Проверено 26 августа 2022 г.
  6. ^ Типы указателей (Руководство по программированию на C#)
  7. ^ Jump up to: а б Арчер , Часть 2, Глава 4: Система типов
  8. ^ «Обобщенные шаблоны (Руководство по программированию на C#)» . Майкрософт . Проверено 7 августа 2011 г.
  9. ^ «Введение в дженерики C#» . Майкрософт.
  10. ^ «Различия между шаблонами C++ и дженериками C#» . Майкрософт.
  11. ^ «Введение в дженерики C#» . Майкрософт . Январь 2005 года . Проверено 18 июня 2009 г.
  12. ^ Ограничения на параметры типа (Руководство по программированию на C#) в Microsoft MSDN
  13. ^ "урожай" . Справочник по языку C# . Майкрософт . Проверено 26 апреля 2009 г.
  14. ^ «.NET Framework — что нового в C# 7.0» . msdn.microsoft.com . Проверено 8 апреля 2017 г.
  15. ^ «Мысли о локальных функциях C# 7» . Антон Сизиков . 15 апреля 2016 г. Проверено 8 апреля 2017 г.
  16. ^ «Директивы препроцессора C#» . Справочник по языку C# . Майкрософт . Проверено 18 июня 2009 г.
  17. ^ «Комментарии к документации» . Microsoft Learn . 15 июня 2023 г.
  18. ^ Хортон, Энсон (11 сентября 2006 г.). «Часто задаваемые вопросы по комментариям к XML-документации C#» . Проверено 11 декабря 2007 г.
  19. ^ Jump up to: а б «Разграничители тегов документации» . Справочник программиста C# . Майкрософт . Архивировано из оригинала 20 декабря 2008 года . Проверено 18 июня 2009 г.
  20. ^ Мартин, Роберт К. (11 августа 2008 г.). «7. Обработка ошибок. Используйте непроверяемые исключения». Чистый код: Справочник по гибкому программному обеспечению . Прентис Холл Интернэшнл. ISBN  978-0132350884 .
  1. Арчер, Том (2001). Внутри С# . Майкрософт Пресс. ISBN  0-7356-1288-9 .
  2. Барт де Смет на Spec #. Архивировано 29 октября 2010 г. в Wayback Machine.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 2811205be5ce28193af16cdeb02082db__1722035220
URL1:https://arc.ask3.ru/arc/aa/28/db/2811205be5ce28193af16cdeb02082db.html
Заголовок, (Title) документа по адресу, URL1:
C Sharp syntax - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)