Тип возвращаемого значения метода

Тип возвращаемого значения метода

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

Объявление методов

В C# определение метода состоит из любых модификаторов (таких как спецификация доступности), типа возвращаемого значения, за которым следует имя метода, затем список аргументов в круглых скобках и далее — тело метода в фигурных скобках:

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

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

Возврат из метода и возврат значения

В целом, возврат из метода может произойти при двух условиях. Во-первых, когда встречается фигурная скобка, закрывающая тело метода. И во-вторых, когда выполняется оператор return. Имеются две формы оператора return: одна — для методов типа void (возврат из метода), т.е. тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения (возврат значения).

Давайте рассмотрим пример:

Использование параметров

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

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

Давайте рассмотрим пример:

Обратите внимание, что значение i осталось неизменным, но измененные значения в myArr также изменились в исходном массиве arr1, так как массивы являются ссылочными типами.

Поведение строк также отличается. Дело в том, что строки являются неизменными (изменение значения строки приводит к созданию совершенно новой строки), поэтому строки не демонстрируют поведение, характерное для ссылочных типов. Любые изменения, проведенные в строке внутри метода, не влияют на исходную строку.

Терминологические заморочки

В языке С, дедушке языка C#, все было очень просто: данные это числа, строки, массивы; программный код – операторы языка и функции. Функции в C, говоря языком структурного программирования, это подпрограммы.

С переходом от императивного языка C к объектно-ориентированному языку C++ понятие функции (как подпрограммы) сохранилось, однако каждая функция стала принадлежать какому-либо классу. Отметим что в С++ были добавлены специальные функции – конструкторы и деструкторы.

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

Разберемся с терминами и понятиями более подробно.

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

Авторы языка определили, что функции-члены — это члены, которые обеспечивают некоторую функциональность для манипулирования данными класса. Они включают методы, свойства, конструкторы, финализаторы (деструкторы в С++), операции и индексаторы.

Для начинающего программиста важно освоить, прежде всего, работу с методами класса, а по сути (в прежнем понимании) – с функциями как подпрограммами. К этому добавим работу с конструкторами классов, а все остальное будет рассмотрено позже.

Шаблон объявления метода

[модификаторы] тип_возвращаемого_значения ИмяМетода([параметры])
<
// Тело метода
>
В C# определение метода состоит из указания модификаторов (static, public и т.п., модификаторы не обязательны), типа возвращаемого значения, имени метода и списка параметров в круглых скобках. Далее в фигурных скобках записывается тело метода.
Каждый параметр состоит из имени типа параметра и имени, по которому к нему можно обратиться в теле метода.

Возврат из метода и возврат значения

Если метод возвращает значение, то для указания точки выхода должен использоваться оператор возврата return вместе с возвращаемым значением. Если метод не возвращает ничего, то в качестве типа возврата указывается void (опустить тип возврата невозможно).

Читайте также:  Драйвера на джойстик xbox 360 windows 7

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

В целом, возврат из метода может произойти при двух условиях. Во-первых, когда встречается фигурная скобка, закрывающая тело метода. И во-вторых, когда выполняется оператор return. Имеются две формы оператора return: одна — для методов типа void (возврат из метода), т.е. тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения.

Использование параметров

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

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

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

Если переменная, указанная в списке параметров, относится к типу значений (int, double, bool и т.п.), то вызываемый метод получает копию этой переменной, а это значит, что все изменения в ней, выполненные внутри метода будут утеряны.

Если переменная из списка параметров относится к ссылочному типу (например, массив), то параметр передается по ссылке, вызываемый метод получает саму переменную, поэтому любые изменения, которым она подвергнется внутри метода, останутся в силе после его завершения.

Поведение строк также отличается. Дело в том, что строки являются неизменными (изменение значения строки приводит к созданию совершенно новой строки), поэтому строки не демонстрируют поведение, характерное для ссылочных типов. Любые изменения, проведенные в строке внутри метода, не влияют на исходную строку.

Передача структуры (struct) как параметра через ее имя также произойдет через копирование (помните, структура относится к типу значений).

Если же для каких-либо типов данных необходима передача по ссылке (она более эффективна при большом объеме данных, который приходится копировать), то перед указанием типа параметра достаточно указать модификатор ref (reference – ссылка, англ.).

Рассмотрим три примера.

ПРИМЕР 1. В статье Первая программа на языке Си шарп мы разбирали программу:

В классе Program объявляется метод Main() (главная функция приложения), при выполнении которого вызываются два метода класса Console: WriteLine() (вывод строки текста) и ReadKey() (чтение символа с клавиатуры).

Ключевое слово static означает, что данный метод принадлежит классу Program.

Модификатор void указывает, что метод не возвращает никаких параметров.

Метод Main() в качестве списка параметров имеет массив строк, метод WriteLine() имеет один параметр – строку, метод ReadKey() параметров не имеет.

ПРИМЕР 2. Объявление метода в примере Вычисление функции sin(x) выглядит так:

Параметром (аргументом) функции объявляется переменная x типа double, метод возвращает результат также типа double (последний оператор метода return s;). Метод является статическим. Для вызова метода достаточно написать оператор y=Sin2(x);

ПРИМЕР 3. Передача параметров по значению, ссылке и через статическую переменную

Объявим в классе Program структуру West с двумя полями, статическую переменную f и метод vp( ):
static void vp(int[] b, West u, string t, double d, ref decimal y)
где b – массив, u – структура, t – строка, d – вещественное число, y – десятичный тип, передается по ссылке (модификатор ref).

В методе изменим эти переменные, а также и f для того, чтобы проверить способы передачи параметров (копированием или по ссылке).

Напечатаем эти значения до и после вызова метода vp().

Результат:

Обратите внимание, что второй элемент массива a[1], десятичное число x (передаваемое через ссылку — ref) и статическая переменная f изменились, а структура u, строка t и вещественное число d не изменились.

Отметим, что статическое поле f, объявленное в классе, доступно методам этого класса без механизма передачи параметров.

Некоторые итоги:

1) переменные, объявленные внутри метода или в списке его параметров, являются локальными переменными;

2) при вызове метода параметры из списка в заголовке метода либо копируются в локальные переменные метода, либо передаются по ссылке;

3) копируются все встроенные типы значений, структуры и (по сути) строки, хотя и они относятся к ссылочным типам;

4) по ссылке передаются массивы и другие объекты. Если их поля будут изменены внутри вызываемого метода, то эти изменения сохранятся при возврате в вызывающий метод;

5) передачу параметров по ссылке (без копирования в локальные переменные метода) можно обеспечить, используя модификатор ref. Однако это не имеет смысла для переменных ссылочного типа («масло масленое»);

6) нет необходимости передавать статические переменные класса через список параметров, в рамках одного класса они имеют смысл глобальных переменных в императивных языках программирования (хотя термин «глобальная переменная» в C# не употребляют);

7) для доступа к данным-членам и функциям-членам других классов необходимо указать имя класса, поставить точку, указать имя члена класса, например: Math.PI — константа, число пи=3,14158… , Math.Tan(x) — тангенс числа x, заданного в радианах;

Читайте также:  Она уже проснулась ты уже пообедал

8) доступ к членам других классов зависит от уровня его приватности (public, но не private или protected).

Как и во многих языках программирования для реализации рекурсивных алгоритмов в C# можно использовать рекурсивные методы.

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

Асинхронные методы могут иметь следующие типы возвращаемых значений: Async methods can have the following return types:

Task для асинхронного метода, который выполняет операцию, но не возвращает значение. Task, for an async method that performs an operation but returns no value.

void для обработчика событий. void , for an event handler.

Начиная с версии 7.0 в языке C# поддерживаются любые типы с доступным методом GetAwaiter . Starting with C# 7.0, any type that has an accessible GetAwaiter method. Объект, возвращаемый методом GetAwaiter , должен реализовывать интерфейс System.Runtime.CompilerServices.ICriticalNotifyCompletion. The object returned by the GetAwaiter method must implement the System.Runtime.CompilerServices.ICriticalNotifyCompletion interface.

Каждый тип возвращаемого значения рассматривается в одном из следующих разделов, а полный пример, в котором используются все три типа, вы найдете в конце этого раздела. Each return type is examined in one of the following sections, and you can find a full example that uses all three types at the end of the topic.

Задача Тип возвращаемого значения Task Return Type

Тип возвращаемого значения Task используется для асинхронного метода, содержащего инструкцию return (C#), в которой операнд имеет тип TResult . The Task return type is used for an async method that contains a return (C#) statement in which the operand has type TResult .

В следующем примере асинхронный метод GetLeisureHours содержит инструкцию return , которая возвращает целое число. In the following example, the GetLeisureHours async method contains a return statement that returns an integer. Поэтому в объявлении метода должен указываться тип возвращаемого значения Task . Therefore, the method declaration must specify a return type of Task . Асинхронный метод FromResult представляет собой заполнитель для операции, которая возвращает строку. The FromResult async method is a placeholder for an operation that returns a string.

При вызове GetLeisureHours из выражения await в методе ShowTodaysInfo это выражение await извлекает целочисленное значение (значение leisureHours ), хранящееся в задаче, которая возвращается методом GetLeisureHours . When GetLeisureHours is called from within an await expression in the ShowTodaysInfo method, the await expression retrieves the integer value (the value of leisureHours ) that’s stored in the task returned by the GetLeisureHours method. Дополнительные сведения о выражениях await см. в разделе await. For more information about await expressions, see await.

Чтобы лучше понять, как это происходит, отделите вызов метода GetLeisureHours от применения await , как показано в следующем коде. You can better understand how this happens by separating the call to GetLeisureHours from the application of await , as the following code shows. Вызов метода GetLeisureHours , который не ожидается немедленно, возвращает Task , как и следовало ожидать из объявления метода. A call to method GetLeisureHours that isn’t immediately awaited returns a Task , as you would expect from the declaration of the method. В данном примере эта задача назначается переменной integerTask . The task is assigned to the integerTask variable in the example. Поскольку integerTask является Task , она содержит свойство Result типа TResult . Because integerTask is a Task , it contains a Result property of type TResult . В этом примере TResult представляет собой целочисленный тип. In this case, TResult represents an integer type. Если выражение await применяется к integerTask , выражение await вычисляется как содержимое свойства Result объекта integerTask . When await is applied to integerTask , the await expression evaluates to the contents of the Result property of integerTask . Это значение присваивается переменной ret . The value is assigned to the ret variable.

Свойство Result является блокирующим свойством. The Result property is a blocking property. При попытке доступа к нему до завершения его задачи поток, который в текущий момент активен, блокируется до того момента, пока задача не будет завершена, а ее значение не станет доступным. If you try to access it before its task is finished, the thread that’s currently active is blocked until the task completes and the value is available. В большинстве случаев следует получать доступ к этому значению с помощью await вместо прямого обращения к свойству. In most cases, you should access the value by using await instead of accessing the property directly.
В предыдущем примере извлекалось значение свойства Result для блокировки основного потока. Это позволяет закончить выполнение метода ShowTodaysInfo до того, как завершится работа приложения. The previous example retrieved the value of the Result property to block the main thread so that the ShowTodaysInfo method could finish execution before the application ended.

Тип возвращаемого значения Task Task Return Type

Асинхронные методы, не содержащие инструкцию return или содержащие инструкцию return , которая не возвращает операнд, обычно имеют тип возвращаемого значения Task. Async methods that don’t contain a return statement or that contain a return statement that doesn’t return an operand usually have a return type of Task. При синхронном выполнении такие методы возвращают void . Such methods return void if they run synchronously. Если для асинхронного метода вы используете тип возвращаемого значения Task, вызывающий метод может использовать оператор await для приостановки выполнения вызывающего объекта до завершения вызванного асинхронного метода. If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller’s completion until the called async method has finished.

Читайте также:  Как обновить антивирус на ноутбуке

В следующем примере асинхронный метод WaitAndApologize не содержит инструкцию return , в связи с чем он возвращает объект Task. In the following example, the WaitAndApologize async method doesn’t contain a return statement, so the method returns a Task object. Это позволяет реализовать ожидание WaitAndApologize . This enables WaitAndApologize to be awaited. Обратите внимание, что тип Task не имеет возвращаемого значения и, соответственно, не содержит свойство Result . Note that the Task type doesn’t include a Result property because it has no return value.

WaitAndApologize вызывается и ожидается с помощью инструкции await (вместо выражения await), похожей на инструкцию вызова для синхронного метода, возвращающего значение void. WaitAndApologize is awaited by using an await statement instead of an await expression, similar to the calling statement for a synchronous void-returning method. Применение оператора await в этом случае не возвращает значение. The application of an await operator in this case doesn’t produce a value.

В следующем коде вызов метода WaitAndApologize отделяется от ожидания задачи, которую возвращает этот метод. The following code separates calling the WaitAndApologize method from awaiting the task that the method returns.

Тип возвращаемого значения Void Void return type

Тип возвращаемого значения void используется в асинхронных обработчиках событий, для которых требуется тип возвращаемого значения void . You use the void return type in asynchronous event handlers, which require a void return type. Поскольку методы, не являющиеся обработчиками событий, не возвращают значения, вместо этого необходимо вернуть Task. Это вызвано тем, что для асинхронных методов, возвращающих значение void , ожидание невозможно. For methods other than event handlers that don’t return a value, you should return a Task instead, because an async method that returns void can’t be awaited. Любой вызывающий объект такого метода должен иметь возможность завершить свою работу, не дожидаясь завершения вызванного асинхронного метода, и он не должен зависеть ни от каких значений и исключений, создаваемых асинхронным методом. Any caller of such a method must be able to continue to completion without waiting for the called async method to finish, and the caller must be independent of any values or exceptions that the async method generates.

Вызывающий объект асинхронного метода, возвращающего void, не может перехватывать исключения, создаваемые методом, и такие необработанные исключения могут привести к сбою приложения. The caller of a void-returning async method can’t catch exceptions that are thrown from the method, and such unhandled exceptions are likely to cause your application to fail. Если исключение возникает в асинхронном методе, который возвращает Task или Task , исключение хранится в возвращенной задаче и повторно вызывается при ожидании задачи. If an exception occurs in an async method that returns a Task or Task , the exception is stored in the returned task and is rethrown when the task is awaited. Поэтому убедитесь, что любой асинхронный метод, который может вызвать исключение, имеет тип возвращаемого значения Task или Task и что вызовы метода являются ожидаемыми. Therefore, make sure that any async method that can produce an exception has a return type of Task or Task and that calls to the method are awaited.

Дополнительные сведения о перехвате исключений в асинхронных методах см. в разделе Исключения в асинхронных методах в статье о try-catch. For more information about how to catch exceptions in async methods, see the Exceptions in Async Methods section of the try-catch topic.

В следующем примере показано поведение асинхронного обработчика событий. The following example shows the behavior of an async event handler. Обратите внимание, что в примере кода асинхронный обработчик событий должен сообщить основному потоку о завершении своей работы. Note that in the example code, an async event handler must let the main thread know when it finishes. Основной поток может ожидать завершения работы асинхронного обработчика событий перед выходом из программы. Then the main thread can wait for an async event handler to complete before exiting the program.

Обобщенные асинхронные типы возвращаемых значений и ValueTask Generalized async return types and ValueTask

Начиная с C# 7.0 асинхронные методы могут возвращать любой тип, имеющий доступный метод GetAwaiter . Starting with C# 7.0, an async method can return any type that has an accessible GetAwaiter method.

Ссылка на основную публикацию
Тест для определения цвета волос
Пожалуйста, не копируйте понравившиеся вам статьи незаконно. Мы предлагаем вам разместить активную ссылку на наш сайт в случае, если вы...
Стим показывает что я не в сети
Не редко пользователи Steam встречаются с проблемой, когда подключение к интернету есть, браузеры работают, но клиент Стим не грузит страницы...
Стим саппорт украли аккаунт
Если ваш аккаунт Steam украли или взломали, то до его восстановления вам необходимо выполнить действия, указанные ниже, иначе аккаунт может...
Тест графики видеокарты 3dmark
Наиболее известная программа тестирования производительности, ставшая де-факто стандартом и точкой отсчета в измерениях игровых возможностей видеокарт. Основную популярность программе обеспечило...
Adblock detector