Главная страница
Навигация по странице:

  • 3.5.1 Перегрузка методов Язык C допускает наличие в классе нескольких методов с одинаковым иден- тификатором. Такое описание называется перегрузкой методов

  • 3.5.2 Новое в версии C 4.0

  • Конспект лекций (C#)-unlocked. 1 Основные сведения о C# Особенности языка


    Скачать 1.97 Mb.
    Название1 Основные сведения о C# Особенности языка
    Дата15.01.2019
    Размер1.97 Mb.
    Формат файлаpdf
    Имя файлаКонспект лекций (C#)-unlocked.pdf
    ТипДокументы
    #63730
    страница6 из 13
    1   2   3   4   5   6   7   8   9   ...   13

    немедленному выходу из метода.
    Оператор return может применяться и в методах, имеющих возвращаемый тип void
    , для немедленного выхода их метода. В этом случае, никакого значения после оператора return не указывается.
    Работа с данными через методы, а не напрямую, позволяет создавать более надёжные программы, а также производить первичную обработку данных. Напри- мер, в методе
    SetSType из заданного строкового представления типа фигуры уда- ляются все концевые пробелы и осуществляется контроль, чтобы данное поле имело хоть какое-нибудь значение.
    Внесение изменений в класс изменит способы работы с полем sType
    :
    Figure firstFigure = new Figure();
    // firstFigure.sType = "Квадрат"; // Теперь этот оператор недопустим firstFigure.SetSType("Квадрат"); // Правильный способ задать значение
    Метод может возвращать не только переменные типов значения, но и создан- ные в методе объекты (в том числе строки, массивы, т.е. элементы любого ссылоч-
    ного типа). Например, дополним класс
    Figure методом дублирования объекта:

    51 public Figure Duplicate()
    {
    Figure tempFigure = new Figure(); tempFigure.sType = sType; tempFigure.posX = posX; tempFigure.posY = posY; return tempFigure;
    }
    Объект, созданный в методе и возвращаемый из него не уничтожается при
    выходе из метода. Он будет уничтожен, как только не будет ссылок на него после окончания работы метода.
    Параметры, указанные в описании метода, называются формальными пара- метрами (параметр n_sType в методе
    SetSType
    ), в то время как параметры, ука- занные при вызове метода – фактическими (например, слово «Квадрат» в послед- ней строки примера, показанного выше). При выполнении метода каждому фор- мальному параметру присваивается значение фактического, однако метод присваи- вания зависит от модификатора параметра:

    если модификатор не указан, то формальному параметру присваивается копия фактического. Поэтому изменение формального параметра внутри метода не ска- жется на значении фактического параметра. В качестве фактического параметра может выступать переменная, константное значение, результат вычислений и т.д.;

    ref
    – параметр передаётся по ссылке, поэтому изменение формального параметра в методе приведёт к изменению фактического параметра. В качестве фактическо- го параметра должна использоваться инициализированная переменная. При вы- зове метода перед фактическим параметром также указывается ключевое слово ref
    ;

    out
    – параметр передаётся по ссылке, поэтому изменение формального параметра в методе приведёт к изменению фактического параметра. В качестве фактическо- го параметра должна использоваться переменная, которая может быть неинициа-
    лизированной. В методе формальному параметру должно быть присвоено зна- чение. При вызове метода перед фактическим параметром также указывается ключевое слово out
    ;

    params
    – позволяет определить параметр метода, принимающий аргумент, в ко- тором количество аргументов является переменным. В объявлении метода после ключевого слова params дополнительные параметры не допускаются, и в объяв- лении метода допускается только одно ключевое слово params
    . Параметр должен быть одномерным массивом, а все фактические параметры должны быть совме- стимы с типом элемента массива. Например: class MyClass
    { public int Sum(params int[] mas)
    { int sum=0; for (int i=0; i

    52 return sum;
    }
    }
    MyClass c = new MyClass(); int[] m = new int[4] {5,6,7,8}; int s1 = c.Sum(m); // s1 = 26 int s2 = c.Sum(1, 2, 3); // s2 = 6 int s3 = c.Sum(1, 2.1, 3); // ошибка
    У метода идентификаторы формальных параметров могут совпадать с иден- тификаторами полей класса, к которому принадлежит метод. В этом случае, внутри метода видимым является формальный параметр, а для доступа к полю класса мо- жет быть использовано ключевое слово
    this
    , например: class MyClass
    { private int x; public void SetX(int x)
    { this.x = x;
    }
    }
    Ключевое слово this означает объект, который вызвал метод, поэтому оно может быть использовано в любом методе класса, например, в конструкторе.
    3.5.1
    Перегрузка методов
    Язык C# допускает наличие в классе нескольких методов с одинаковым иден- тификатором. Такое описание называется перегрузкой методов. В этом случае все методы с одинаковым идентификатором должны отличаться количеством и/или ти- пом параметров. Это требование необходимо для того, чтобы компилятор мог рас- познать необходимый для применения метод. Если ни один метод не подходит для заданного набора параметров, то программа не может быть скомпилирована.
    Пример: класс, в котором определено вещественное поле и перегруженный метод, позволяющий выдавать значение этого поля в разных форматах. class MyClass
    { public double d; public string GetD()
    { return d.ToString();
    } public string GetD(int n)
    { return String.Format("{0:F"+n+"}",d);
    }

    53 public string GetD(int n, char c)
    { return String.Format("{0:"+c+n+"}", d);
    }
    }
    MyClass c = new MyClass(); c.d = 1234.567; string s1 = c.GetD(); // s1 = "1234,567" string s2 = c.GetD(2); // s2 = "1234,57" string s3 = c.GetD(2,'N'); // s3 = "1 234,57"
    При перегрузке методов возможно изменение возвращаемого типа, но только с изменением типа и/или количества параметров.
    Пример: класс, имеющий перегруженный метод, выполняющий целочислен- ное или обычное деление одного числа на другое в зависимости от их типа. class MyClass
    { public int Divide(int a, int b)
    { return a/b;
    } public double Divide(double a, double b)
    { return a/b;
    }
    }
    MyClass c = new MyClass(); int i = c.Divide(7,2); // i = 3 double d1 = c.Divide(7,2); // d1 = 3 double d2 = c.Divide(7,2.0); // d2 = 3.5
    Перегруженные методы могут иметь одинаковое количество и тип параметров в случае, если в одной реализации метода часть параметров передаётся по ссылке
    (
    ref или out
    ), а в другой – по значению. public void Method(int a) {...}; public void Method(ref int a) {...};
    Однако нельзя перегрузить метод, если в одной реализации передача осу- ществляется по ссылке out
    , а в другой – по ссылке ref public void Method(out int a) {...}; public void Method(ref int a) {...};

    54
    3.5.2
    Новое в версии C# 4.0
    Начиная с версии C# 4.0 параметрам метода, конструктора или индексатора могут быть заданы значения по умолчанию. Это позволяет делать параметры необя- зательными. Для указания значения по умолчанию необходимо при описании пара- метра присвоить ему значение, например: public class MyClass
    { public int Method(int a = 1, int b = 1, int c = 1)
    { return a * b * c;
    }
    }
    MyClass cl = new MyClass(); int i1 = cl.Method(2, 3, 4); // i1 = 24 int i2 = cl.Method(5, 6); // i2 = 30 int i3 = cl.Method(7); // i3 = 7 int i4 = cl.Method(); // i4 = 1
    Если в методе требуются обязательные и необязательные параметры, то в опи- сании метода обязательные параметры должны указываться первыми, т.е. описа- ние метода public int Method(int a = 1, int b, int c = 1) {return a * b * c;} будет недопустимым.
    Введение для параметров значений по умолчанию может привести к сложно- стям при использовании перегрузки методов, например: public class MyClass
    { public int Method(int a, int b = 1)
    { return a * b;
    } public double Method(int a, double b = 1.0)
    { return a * b;
    }
    }
    MyClass cl = new MyClass(); int i = cl.Method(2, 3); // i = 6 double d = cl.Method(2, 3.0); // d = 6.0 d = cl.Method(2); // Неоднозначность i = cl.Method(2); // Неоднозначность
    В строке d = cl.Method(2);
    возникает неоднозначность, т.к. компилятор не мо- жет определить, какой из перегруженных методов использовать. Изменение типа

    55 возвращаемого значения для сужения диапазона возможных значений
    (
    i = cl.Method(2)
    ) также не приведёт к устранению неоднозначности. В таких случаях, лучше не использовать значения по умолчанию в перегружаемых методах.
    Ещё одним новшеством при работе с методами является возможность исполь- зовать имена параметров при вызове метода. Формат описания параметра при этом имеет вид:
    <идентификатор параметра> : <значение>
    Применение именованных параметров позволяет указывать их не в той после- довательности, в которой они описаны в методе, например: public class MyClass
    { public int Method(int a, int b)
    { return a - b;
    }
    }
    MyClass cl = new MyClass(); int i1 = cl.Method(5, 3); // i1 = 2 int i2 = cl.Method(a: 5, b: 3); // i2 = 2 int i3 = cl.Method(b: 5, a: 3); // i3 = -2 int i4 = cl.Method(5, b: 3); // i4 = 2 int i5 = cl.Method(5, a: 3); // Ошибка
    Строка (
    int i5 = cl.Method(5, a: 3)
    ) недопустима, т.к. в ней выполня- ется повторное присваивание значения параметру «
    a
    ».
    Именованные параметры могут применяться в комбинации с значениями по умолчанию, что позволяет указывать при вызове метода только требуемые парамет- ры, например: public class MyClass
    { public double Method(double a = 1.0, double b = 1.0, double c = 1.0)
    { return (a - b) / c;
    }
    }
    MyClass cl = new MyClass(); double d1 = cl.Method(a: 2); // d1 = 1 double d2 = cl.Method(b: 2); // d2 = -1 double d3 = cl.Method(c: 2); // d3 = 0

    56
    3.6
    Конструкторы
    Конструкторы представляют собой специальные методы, вызываемые при со- здании объекта. Каждый класс имеет конструктор по умолчанию
    1
    , не имеющий па- раметров и устанавливающий значения всех членов-данных в «нулевое» состояние
    (если не переопределён), а также может иметь произвольное количество конструк- торов с разным набором параметров.
    Основное назначение конструктора – инициализация членов-данных и подго- товка объекта к работе.
    Формальная схема конструктора имеет вид:
    <доступ> <имя_класса>([<список параметров>])
    {
    <тело конструктора>
    }
    Чаще всего
    <доступ>
    имеет значение public
    , т.к. конструктор вызывается при создании объектов из-за пределов класса.
    В классе может быть описано несколько конструкторов, т.е. конструкторы, как и любые методы, могут быть перегружены.
    Пример: дополним класс
    Figure конструкторами с разными наборами пара- метров. Будем считать, что значения по умолчанию для полей posX
    , posY
    – 1, а для поля sType
    – «Не задан». Инициализацию полей posX
    , posY
    , для примера, будем проводить только в конструкторах. class Figure
    { private string sType="Не задан"; public int posX, posY; public string GetSType()
    { return sType;
    } public void SetSType(string n_sType)
    { if (n_sType.Trim() != "") sType = n_sType.Trim();
    } public Figure Duplicate()
    { return new Figure(sType,posX,posY);
    } public Figure() // Переопределение конструктора по умолчанию
    { posX = posY = 1;
    } public Figure(string n_sType) // Конструктор с одним параметром
    1
    Конструктор по умолчанию скрывается, если определен хотя бы один другой конструктор.

    57
    {
    SetType(n_sType); posX = posY = 1;
    }
    // Конструктор с тремя параметрами public Figure(string n_sType, int n_posX, int n_posY)
    {
    SetType(n_sType); posX = n_posX; posY = n_posY;
    }
    }
    // Вызов конструктора по умолчанию
    Figure figure1 = new Figure();
    // Вызов конструктора с одним параметром
    Figure figure2 = new Figure("Квадрат");
    // Вызов конструктора с тремя параметрами
    Figure figure3 = new Figure("Круг",5,6);
    // Ошибка: конструктора с одним целочисленным параметром нет
    // Figure figure4 = new Figure(5);
    Также в приведённом выше примере был изменён метод
    Duplicate
    , т.к. имея конструктор с параметрами можно легко создать объект с копией свойств.
    Если у класса определено несколько конструкторов, то один из них может вы- зывать другой. Для этого используется конструкция вида:
    <доступ> <имя_класса>([<список параметров1>]) : this([<список параметров2>])
    {
    <тело конструктора>
    }
    Здесь
    <список параметров1>
    определяет набор формальных параметров текущего конструктора, а
    <список параметров2>
    – набор фактических парамет- ров вызываемого конструктора. При этом, в
    <список параметров2>
    могут ис- пользоваться параметры из
    <список параметров1>
    В некоторых случаях
    <тело конструктора>
    может оставаться пустым, т.к. все действия выполняются в другом вызываемом конструкторе.
    Например, конструкторы без параметров и с одним параметром из приведён- ного выше примера могут быть описаны с использованием конструктора с тремя па- раметрами следующим образом: public Figure() : this("Не задан",1,1)
    {
    } public Figure(string n_sType) : this(n_sType,1,1)
    {
    }

    58
    Если один конструктор вызывает другой, то сначала выполняется вызываемый конструктор, а потом вызывающий.
    В отличии от некоторых других языков программирования в C# отсутствует конструктор копии, но его можно создать самостоятельно. Например, вышеприве- дённый класс может быть дополнен таким конструктором: public Figure(Figure sourceFigure)
    { sType = sourceFigure.sType; posX = sourceFigure.posX; posY = sourceFigure.posY;
    }
    Реализованный конструктор копии в сочетании с ключевым словом this поз- воляет улучшить метод
    Duplicate следующим образом: public Figure Duplicate()
    { return new Figure(this);
    }
    Применение конструктора копий целесообразнее, чем просто конструктора с параметрами, т.к. по определению этот конструктор должен полностью копировать все члены-данные существующего объекта, в то время, как любой конструктор с па- раметрами может использовать только часть членов-данных класса.
    3.7
    Деструкторы
    В языке С# имеется возможность определить метод, который будет вызывать- ся непосредственно перед окончательным уничтожением объекта. Такой метод называется деструктором и может использоваться в ряде особых случаев.
    Формальная схема деструктора имеет вид:

    <имя_класса>()
    {
    <тело деструктора>
    }
    Деструктор вызывается непосредственно перед «сборкой мусора». Это означа- ет, что заранее нельзя знать, когда именно следует вызывать деструктор
    1
    . Кроме то- го, программа может завершиться до того, как произойдёт «сборка мусора», а следо- вательно, деструктор может быть вообще не вызван.
    Как правило, деструктор должен воздействовать только на переменные экзем- пляра, определённые в его классе.
    1
    Существует возможность принудительно выполнить «сборку мусора», вызвав метод Collect, но в боль- шинстве случаев этого следует избегать, потому что это может привести к проблемам с производительностью.

    59
    Деструктор не имеет возвращаемого параметра, спецификатора доступа, спис- ка принимаемых параметров и не может быть перегружен.
    В силу редкого применения деструкторов в С#, для класса
    Figure описывать деструктор не будем.
    3.8
    Инициализаторы объектов
    Задание начальных свойств объекта возможно при его создании, даже если класс не имеет конструкторов с параметрами. Для этого используется структура с
    инициализаторами, формальный вид которой: new <идентификатор класса>[(<параметры>)]
    {<идентификатор 1>=<значение 1> [,<идентификатор 2>=<значение 2> ...
    ]}; где

    <идентификатор N>
    – идентификатор поля или свойства;

    <значение N>
    – значение, присваиваемое полю или свойству.
    При создании объекта с помощью инициализаторов сначала вызывается тре- буемый конструктор, а затем указанным полям и свойствам присваиваются задан- ные значения. Порядок следования полей значения не имеет.
    Пример: создания объекта класса
    Figure с начальным значением posY
    рав- ным 10 с помощью инициализаторов.
    Figure firstFigure = new Figure {posY=10};
    // sType="Не задан", posX=1, posY=10
    Figure firstFigure = new Figure("Круг") {posY=10};
    // sType="Круг", posX=1, posY=10
    3.9
    Свойства
    Свойство – это программная конструкция, обладающая следующими характе- ристиками:

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

    свойство выглядит для использующего его как поле. Это упрощает синтаксис за счёт лёгкого использования свойства в выражениях и задания значения свойства с помощью операторов присваивания.
    Формальная схема описания свойства имеет вид:
    [<доступ>] <тип> <идентификатор> {get {<код метода доступа get>} set
    {<код метода доступа set>}}

    60 где:

    <код метода доступа get>
    – код, определяющий действия, выполняемые при запросе значения свойства;

    <код метода доступа set>
    – код, определяющий действия, выполняемые при установке значения свойства.
    Метод доступа get должен содержать оператор return
    , определяющий зна- чение, возвращаемое методом get при запросе значения свойства.
    Метод доступа set имеет неявно заданный параметр value
    , который позво- ляет указать значение, присваиваемое свойству.
    Однако свойство само по себе не хранит никакого значения, поэтому оно должно либо быть соотнесено с некоторым полем, объявленным в классе (как пра- вило, с спецификатором доступа private
    ), либо быть расчётным на основе других членов класса.
    Пример: перепишем класс
    Figure с применением свойств. Будут использова- ны следующие методы именования идентификаторов: поля класса начинаются с символа «_»; свойства – идентификатор поля без символа «_». На положение фигу- ры накладывается ограничение: координаты не могут быть отрицательными. class Figure
    { private string _sType; private int _posX, _posY; public string sType
    { get { return _sType; } set { if (value.Trim() != "") _sType = value.Trim(); }
    } public int posX
    { get { return _posX; } set { if (value >= 0) _posX = value; }
    } public int posY
    { get { return _posY; } set { if (value >= 0) _posY = value; }
    } public Figure Duplicate()
    { return new Figure(this);
    } public Figure() : this("Не задан",1,1)
    {
    } public Figure(string n_sType) : this(n_sType,1,1)
    {
    } public Figure(string n_sType, int n_posX, int n_posY)
    {
    _sType = n_sType.Trim() != "" ? n_sType.Trim() : "Не задан";

    61
    _posX = n_posX >= 0 ? n_posX : 1;
    _posY = n_posY >= 0 ? n_posY : 1;
    } public Figure(Figure sourceFigure)
    {
    _sType = sourceFigure._sType;
    _posX = sourceFigure._posX;
    _posY = sourceFigure._posY;
    }
    }
    Figure firstFigure = new Figure();
    // Теперь этот оператор снова допустим, но контроль ввода также
    // проводится firstFigure.sType = "Квадрат";
    Если при описании свойства не указан метод set
    , то свойство доступно толь- ко для чтения, а если метод get
    – то только для записи.
    1   2   3   4   5   6   7   8   9   ...   13


    написать администратору сайта