Студопедия

Главная страница Случайная страница

КАТЕГОРИИ:

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Вызов метода. Семантика






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

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

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

Каково следствие семантики вызова по значению? Если вы забыли указать ключевое слово ref или out для аргумента, фактически являющегося выходным, то к нему будет применяться вызов по значению. Даже если в теле метода происходит изменение значения этого аргумента, оно действует только на время выполнения тела метода. Как только метод заканчивает свою работу (завершается блок), все локальные переменные (в том числе созданные для замены формальных аргументов) оканчивают свое существование, так что изменения не затронут фактических аргументов, и они сохранят свое значение, бывшее у них до вызова. Отсюда вывод: все выходные аргументы значимых типов, значения которых предполагается изменить в процессе работы, должны иметь ключевое слово ref или out.

Говоря о семантике вызова по ссылке и по значению, следует сделать важное уточнение. В объектном программировании, каковым является и программирование на C#, основную роль играют ссылочные типы - мы работаем с классами и объектами. Когда методу передается объект ссылочного типа, все поля этого объекта могут в методе меняться самым беззастенчивым образом. И это несмотря на то, что объект формально не является выходным, не имеет ключевых слов ref или out, использует семантику вызова по значению. Сама ссылка на объект при этом, как и положено, остается неизменной, но состояние объекта, его поля могут полностью обновиться. Такая ситуация типична и представляет один из основных способов изменения состояния объектов. Именно поэтому ref или out не столь часто появляются при описании аргументов метода.

Методы. Перегрузка

Должно ли быть уникальным имя метода в классе? Нет, это не требуется. Более того, проектирование методов с одним и тем же именем является частью стиля программирования на С++ и стиля C#. Существование в классе методов с одним и тем же именем называется перегрузкой, а сами одноименные методы называются перегруженными.

Перегрузка методов полезна, когда требуется решать подобные задачи с разным набором аргументов. Типичный пример - это нахождение площади треугольника. Площадь можно вычислить по трем сторонам, по двум углам и стороне, по двум сторонам и углу между ними и при многих других наборах аргументов. Считается удобным во всех случаях иметь для метода одно имя, например, Square, и всегда, когда нужно вычислить площадь, не задумываясь вызывать метод Square, передавая ему известные в данный момент аргументы. Без перегрузки пришлось бы давать различные имена всем функциям, а главное, помнить их!

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

Перегрузка требует уточнения семантики вызова метода. Когда встречается вызов не перегруженного метода, то имя метода в вызове однозначно определяет, тело какого метода должно выполняться в точке вызова. Когда же метод перегружен, то знания имени недостаточно - оно не уникально. Уникальной характеристикой перегруженных методов является их сигнатура. Перегруженные методы, имея одинаковое имя, должны отличаться либо числом аргументов, либо их типами, либо ключевыми словами (заметьте, с точки зрения сигнатуры ключевые слова ref и out не отличаются, а модификатор params в сигнатуру не входит). Уникальность сигнатуры позволяет вызвать требуемый перегруженный метод.

Выше уже были приведены четыре перегруженных метода с именем Cube, отличающиеся сигнатурой. Методы отличаются типами аргументов и ключевым словом params. Когда вызывается метод Cube с двумя аргументами, в зависимости от типа будет вызываться реализация, не содержащая аргумент с модификатором params. Когда же число аргументов больше двух, работает реализация, позволяющая справиться с заранее не фиксированным числом аргументов. Заметьте, эта реализация может прекрасно работать и для случая двух аргументов, но полезно иметь частные случаи для фиксированного набора аргументов. При поиске подходящего перегруженного метода частные случаи получают предпочтение в сравнении с общим случаем.

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

Есть ситуации, где перегрузка полезна, недаром она широко используется при построении библиотеки FCL. Возьмем, например, класс Convert, у которого 16 методов с разными именами, зависящими от целевого типа преобразования. Каждый из этих 16 методов перегружен и, в свою очередь, имеет примерно 16 реализаций в зависимости от типа источника. Согласитесь, что неразумно было бы иметь в классе Convert 256 методов вместо 16 перегруженных методов. Впрочем, так же неразумно было бы иметь один перегруженный метод, имеющий 256 реализаций. Перегрузка - это инструмент, которым следует пользоваться с осторожностью и обоснованно.


Поделиться с друзьями:

mylektsii.su - Мои Лекции - 2015-2024 год. (0.012 сек.)Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав Пожаловаться на материал