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

  • Индексаторы

  • Операторы

  • Методы завершения

  • Отчет по практике по ТРИЗБД в работе с языками C# и Visual basic. Отчет по практике. Оглавление 1 Изм. Лист докум. Подп. Дата 1 Проверил Гатауллина Ф. Ф. 1


    Скачать 1.49 Mb.
    НазваниеОглавление 1 Изм. Лист докум. Подп. Дата 1 Проверил Гатауллина Ф. Ф. 1
    АнкорОтчет по практике по ТРИЗБД в работе с языками C# и Visual basic
    Дата16.12.2020
    Размер1.49 Mb.
    Формат файлаdoc
    Имя файлаОтчет по практике.doc
    ТипДокументы
    #161096
    страница10 из 11
    1   2   3   4   5   6   7   8   9   10   11

    Структура языка программирования C#

    Элементы языка программирования C#


    Члены class могут быть *статическ--ими членами* или *членами экземпляра*. Статические члены принадлежат классу в целом, а члены экземпляра принадлежат конкретным объектам (экземплярам классов).

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

    • *Константы**. Константные значения, связанные с классом.*Constants**: Constant values associated with the class

    • Поля. Переменные, связанные с классом.

    • Методы. Действия, которые может выполнять класс.

    • Свойства. Действия, связанные с чтением и записью именованных свойств класса.

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

    • События. Уведомления, которые могут быть созданы этим классом.

    • Операторы. Поддерживаемые классом операторы преобразования и выражения.

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

    • Методы завершения. Действия, выполняемые перед окончательным удалением экземпляров класса.

    • Типы. Вложенные типы, объявленные в классе.

    Возможности доступа


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

    • public. Доступ не ограничен.

    • private. Доступ возможен только из этого класса.

    • protected. Доступ возможен из этого класса и из классов, производных от него.

    • internal. Доступ ограничен текущей сборкой (.exe или .dll).

    • protected internal. Доступ ограничен данным классом, классами, производными от данного класса, либо классами в той же сборке.

    • private protected. Доступ ограничен данным классом либо классами, производными от данного типа в той же сборке.



    Поля


    Поле является переменной, связанной с определенным классом или экземпляром класса.

    Поле, объявленное с модификатором static, является статическим. Статическое поле определяет строго одно место хранения. Независимо от того, сколько будет создано экземпляров этого класса, существует только одна копия статического поля.

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

    В следующем примере каждый экземпляр класса Color содержит отдельную копию полей экземпляра R, G и B, но для каждого из статических полей Black, White, Red, Green и Blue существует только одна копия:

    public class Color

    {

    public static readonly Color Black = new Color(0, 0, 0);

    public static readonly Color White = new Color(255, 255, 255);

    public static readonly Color Red = new Color(255, 0, 0);

    public static readonly Color Green = new Color(0, 255, 0);

    public static readonly Color Blue = new Color(0, 0, 255);

    public byte R;

    public byte G;

    public byte B;

    public Color(byte r, byte g, byte b)

    {

    R = r;

    G = g;

    B = b;

    }

    }

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

    Методы


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

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

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

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

    Если тело метода является одиночным выражением, метод можно определить с помощью компактного формата выражения, как показано в следующем примере:

    public override string ToString() => "This is an object";

    Параметры


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

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

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

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

    static void Swap(ref int x, ref int y)

    {

    int temp = x;

    x = y;

    y = temp;

    }
    public static void SwapExample()

    {

    int i = 1, j = 2;

    Swap(ref i, ref j);

    Console.WriteLine($"{i} {j}"); // "2 1"

    }

    Параметр вывода используется для передачи аргументов по ссылке. Он похож на ссылочный параметр, однако не требует явно присваивать значение аргумента, предоставляемого вызывающим объектом. Чтобы объявить параметр вывода, используйте модификатор out. В следующем примере показано использование параметров out с помощью синтаксиса, появившегося в C# 7.

    static void Divide(int x, int y, out int result, out int remainder)

    {

    result = x / y;

    remainder = x % y;

    }
    public static void OutUsage()

    {

    Divide(10, 3, out int res, out int rem);

    Console.WriteLine($"{res} {rem}"); // "3 1"

    }

    Массив параметров позволяет передавать в метод переменное число аргументов. Чтобы объявить массив параметров, используйте модификатор params. Массив параметров может быть только последним параметром в методе. Для него можно использовать только тип одномерного массива. В качестве примера правильного использования массива параметров можно назвать методы Write и WriteLine, реализованные в классе System.Console. Ниже представлены объявления этих методов.

    ublic class Console

    {

    public static void Write(string fmt, params object[] args) { }

    public static void WriteLine(string fmt, params object[] args) { }

    // ...

    }

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

    int x, y, z;

    x = 3;

    y = 4;

    z = 5;

    Console.WriteLine("x={0} y={1} z={2}", x, y, z);

    ...эквивалентен следующей конструкции:

    int x = 3, y = 4, z = 5;

    string s = "x={0} y={1} z={2}";

    object[] args = new object[3];

    args[0] = x;

    args[1] = y;

    args[2] = z;

    Console.WriteLine(s, args);

    Тело метода и локальные переменные

    Тело метода содержит инструкции, которые будут выполнены при вызове метода.

    В теле метода можно объявлять переменные, относящиеся к выполнению этого метода. Такие переменные называются локальными переменными. В объявлении локальной переменной нужно указать имя типа и имя переменной. Также можно задать ее начальное значение. Следующий пример кода объявляет локальную переменную i с нулевым начальным значением, и еще одну локальную переменную j без начального значения.
    class Squares

    {

    public static void WriteSquares()

    {

    int i = 0;

    int j;

    while (i < 10)

    {

    j = i * i;

    Console.WriteLine($"{i} x {i} = {j}");

    i = i + 1;

    }

    }

    }

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

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

    Статические методы и методы экземпляра

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

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

    Следующий класс Entity содержит статические члены и члены экземпляра.

    class Entity

    {

    static int s_nextSerialNo;

    int _serialNo;



    public Entity()

    {

    _serialNo = s_nextSerialNo++;

    }



    public int GetSerialNo()

    {

    return _serialNo;

    }



    public static int GetNextSerialNo()

    {

    return s_nextSerialNo;

    }



    public static void SetNextSerialNo(int value)

    {

    s_nextSerialNo = value;

    }

    }

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

    Статические методы GetNextSerialNo и SetNextSerialNo могут обращаться к статическому полю s_nextSerialNo, но прямое обращение из них к полю экземпляра _serialNo приводит к ошибке.

    В приведенном ниже примере показано использование класса Entity.

    Entity.SetNextSerialNo(1000);

    Entity e1 = new Entity();

    Entity e2 = new Entity();

    Console.WriteLine(e1.GetSerialNo()); // Outputs "1000"

    Console.WriteLine(e2.GetSerialNo()); // Outputs "1001"

    Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002"

    Статические методы SetNextSerialNo и GetNextSerialNo вызываются для класса, а метод экземпляра GetSerialNo вызывается для экземпляров класса.

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


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

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

    Виртуальный метод можно переопределить в производном классе. Если объявление метода экземпляра содержит модификатор override, этот метод переопределяет унаследованный виртуальный метод с такой же сигнатурой. Объявление виртуального метода создает новый метод. Переопределение этого метода создает специализированный виртуальный метод с новой реализацией.

    Абстрактным методом называется виртуальный метод без реализации. Абстрактный метод объявляется с модификатором abstract. Его можно объявить только в абстрактном классе. Абстрактный метод должен обязательно переопределяться в каждом производном классе, не являющемся абстрактным.

    Следующий пример кода объявляет абстрактный класс Expression, который представляет узел дерева выражений, а также три производных класса: Constant, VariableReference и Operation, которые реализуют узлы дерева выражений для констант, ссылок на переменные и арифметических операций. (Этот пример похож на типы дерева выражений, но не связан с ними.)

    public abstract class Expression

    {

    public abstract double Evaluate(Dictionary vars);

    }

    public class Constant : Expression

    {

    double _value;

    public Constant(double value)

    {

    _value = value;

    }

    public override double Evaluate(Dictionary vars)

    {

    return _value;

    }

    }

    public class VariableReference : Expression

    {

    string _name;

    public VariableReference(string name)

    {

    _name = name;

    }

    public override double Evaluate(Dictionary vars)

    {

    object value = vars[_name] ?? throw new Exception($"Unknown variable: {_name}");

    return Convert.ToDouble(value);

    }

    }

    public class Operation : Expression

    {

    Expression _left;

    char _op;

    Expression _right;

    public Operation(Expression left, char op, Expression right)

    {

    _left = left;

    _op = op;

    _right = right;

    }

    public override double Evaluate(Dictionary vars)

    {

    double x = _left.Evaluate(vars);

    double y = _right.Evaluate(vars);

    switch (_op)

    {

    case '+': return x + y;

    case '-': return x - y;

    case '*': return x * y;

    case '/': return x / y;

    default: throw new Exception("Unknown operator");

    }

    }

    }

    Четыре приведенных выше класса можно использовать для моделирования арифметических выражений. Например, с помощью экземпляров этих классов выражение x + 3 можно представить следующим образом.

    Expression e = new Operation(

    new VariableReference("x"),

    '+',

    new Constant(3));

    Метод Evaluate экземпляра Expression вызывается для вычисления данного выражения и создает значение double. Этот метод принимает аргумент Dictionary, который содержит имена переменных (в качестве ключей записей) и значения переменных (в качестве значений записей). Так как Evaluate — абстрактный метод, то в неабстрактных классах, производных от Expression, необходимо переопределить Evaluate.

    В Constant реализация метода Evaluate просто возвращает хранимую константу. В VariableReference реализация этого метода выполняет поиск имени переменной в словаре и возвращает полученное значение. В Operation реализация этого метода сначала вычисляет левый и правый операнды (рекурсивно вызывая их методы Evaluate), а затем выполняет предоставленную арифметическую операцию.

    В следующей программе классы Expression используются для вычисления выражения x * (y + 2) с различными значениями x и y.

    Expression e = new Operation(

    new VariableReference("x"),

    '*',

    new Operation(

    new VariableReference("y"),

    '+',

    new Constant(2)

    )

    );

    Dictionary vars = new Dictionary();

    vars["x"] = 3;

    vars["y"] = 5;

    Console.WriteLine(e.Evaluate(vars)); // "21"

    vars["x"] = 1.5;

    vars["y"] = 9;

    Console.WriteLine(e.Evaluate(vars)); // "16.5"

    Перегрузка методов


    Перегрузка метода позволяет использовать в одном классе несколько методов с одинаковыми именами, если они имеют уникальные сигнатуры. Когда при компиляции встречается вызов перегруженного метода, компилятор использует принцип разрешения перегрузки, чтобы определить, какой из методов следует вызвать. Разрешение перегрузки выбирает из методов тот, который лучше всего соответствует предоставленным аргументам. Если не удается выбрать конкретный подходящий метод, возвращается ошибка. В следующем примере показано, как работает разрешение перегрузки. Комментарий к каждому вызову метода UsageExample указывает, какой именно метод вызывается.

    class OverloadingExample

    {

    static void F() => Console.WriteLine("F()");

    static void F(object x) => Console.WriteLine("F(object)");

    static void F(int x) => Console.WriteLine("F(int)");

    static void F(double x) => Console.WriteLine("F(double)");

    static void F(T x) => Console.WriteLine("F(T)");

    static void F(double x, double y) => Console.WriteLine("F(double, double)");

    public static void UsageExample()

    {

    F(); // Invokes F()

    F(1); // Invokes F(int)

    F(1.0); // Invokes F(double)

    F("abc"); // Invokes F(string)

    F((double)1); // Invokes F(double)

    F((object)1); // Invokes F(object)

    F(1); // Invokes F(int)

    F(1, 1); // Invokes F(double, double)

    }

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

    Другие функции-члены


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

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

    public class MyList

    {

    const int DefaultCapacity = 4;
    T[] _items;

    int _count;
    public MyList(int capacity = DefaultCapacity)

    {

    _items = new T[capacity];

    }
    public int Count => _count;
    public int Capacity

    {

    get => _items.Length;

    set

    {

    if (value < _count) value = _count;

    if (value != _items.Length)

    {

    T[] newItems = new T[value];

    Array.Copy(_items, 0, newItems, 0, _count);

    _items = newItems;

    }

    }

    }
    public T this[int index]

    {

    get => _items[index];

    set

    {

    _items[index] = value;

    OnChanged();

    }

    }
    public void Add(T item)

    {

    if (_count == Capacity) Capacity = _count * 2;

    _items[_count] = item;

    _count++;

    OnChanged();

    }

    protected virtual void OnChanged() =>

    Changed?.Invoke(this, EventArgs.Empty);
    public override bool Equals(object other) =>

    Equals(this, other as MyList);
    static bool Equals(MyList a, MyList b)

    {

    if (Object.ReferenceEquals(a, null)) return Object.ReferenceEquals(b, null);

    if (Object.ReferenceEquals(b, null) || a._count != b._count)

    return false;

    for (int i = 0; i < a._count; i++)

    {

    if (!object.Equals(a._items[i], b._items[i]))

    {

    return false;

    }

    }

    return true;

    }

    public event EventHandler Changed;
    public static bool operator ==(MyList a, MyList b) =>

    Equals(a, b);

    public static bool operator !=(MyList a, MyList b) =>

    !Equals(a, b);

    }

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


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

    Конструктор объявляется в виде метода без возвращаемого типа, имя которого совпадает с именем класса, в котором он определен. Если объявление конструктора содержит модификатор static, объявляется статический конструктор. В противном случае это объявление считается конструктором экземпляра.

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

    MyList list1 = new MyList();

    MyList list2 = new MyList(10);

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

    Свойства


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

    Свойство объявляется так же, как поле, за исключением того, что объявление заканчивается не точкой с запятой, а парой разделителей { и }, между которыми указан метод доступа get или set. Свойство, для которого определены акцессоры get и set, является свойством для чтения и записи. Если в свойстве есть только акцессор get, оно является свойством только для чтения, и если только акцессор set — свойством только для записи.

    Акцессор get оформляется как метод без параметров, у которого тип возвращаемого значения совпадает с типом, установленным для этого свойства. Метод доступа set соответствует методу с одним именованным значением параметра и без возвращаемого типа. Метод доступа get вычисляет значение свойства. Метод доступа set предоставляет новое значение для свойства. При ссылке на свойство в качестве назначения в операторе присваивания или в качестве операнда для ++ или -- вызывается метод доступа set. В остальных случаях при ссылке на свойство вызывается метод доступа get.

    Класс MyList объявляет два свойства: Count (только для чтения) и Capacity (только для записи). Следующий код содержит пример использования этих свойств:

    MyList names = new MyList();

    names.Capacity = 100; // Invokes set accessor

    int i = names.Count; // Invokes get accessor

    int j = names.Capacity; // Invokes get accessor

    Как и в отношении полей и методов, C# поддерживает свойства экземпляра и статические свойства. Статические свойства объявляются с модификатором static, а свойства экземпляра — без него.

    Акцессоры свойства могут быть виртуальными. Если объявление свойства содержит модификатор virtual, abstract или override, этот модификатор применяется к акцессорам свойства.

    Индексаторы


    Индексатор является членом, позволяющим индексировать объекты так, как будто они включены в массив. Индексатор объявляется так же, как свойство, за исключением того, что именем элемента является this, а за этим именем следует список параметров, находящийся между разделителями [ и ]. Эти параметры доступны в акцессорах индексатора. Как и свойства, можно объявить индексаторы для чтения и записи, только для чтения или только для записи. Кроме того, поддерживаются виртуальные акцессоры индексатора.

    Класс MyList объявляет один индексатор для чтения и записи, который принимает параметр int. Индексатор позволяет индексировать экземпляры MyList значениями с типом int. Например:

    MyList names = new MyList();

    names.Add("Liz");

    names.Add("Martha");

    names.Add("Beth");

    for (int i = 0; i < names.Count; i++)

    {

    string s = names[i];

    names[i] = s.ToUpper();

    }

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

    Операторы


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

    В классе MyList объявляются два оператора: operator == и operator !=. Эти переопределенные операторы придают новое значение выражениям, которые применяют эти операторы к экземплярам MyList. В частности, они определяют, что равенство двух экземпляров MyList проверяется путем сравнения всех содержащихся в них объектов с помощью определенных для них методов Equals. Следующий пример кода использует оператор == для сравнения двух экземпляров MyList.

    MyList a = new MyList();

    a.Add(1);

    a.Add(2);

    MyList b = new MyList();

    b.Add(1);

    b.Add(2);

    Console.WriteLine(a == b); // Outputs "True"

    b.Add(3);

    Console.WriteLine(a == b); // Outputs "False"

    Первый Console.WriteLine выводит True, поскольку два списка содержат одинаковое число объектов с одинаковыми значениями в том же порядке. Если бы в MyList не было определения operator==, первый Console.WriteLine возвращал бы False, поскольку a и b указывают на различные экземпляры MyList.

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


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

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

    Уничтожение объектов лучше контролировать с помощью инструкции using.

    События


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

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

    Класс MyList объявляет один член события с именем Changed, который обрабатывает добавление нового элемента. Событие Changed вызывается виртуальным методом OnChanged, который сначала проверяет, не имеет ли это событие значение null (это означает, что обработчики отсутствуют). Концепция создания события в точности соответствует вызову делегата, представленного этим событием. Это позволяет обойтись без особой языковой конструкции для создания событий.

    Клиенты реагируют на события посредством обработчиков событий. Обработчики событий можно подключать с помощью оператора += и удалять с помощью оператора -=. Следующий пример кода подключает обработчик события Changed к событию MyList.

    class EventExample

    {

    static int s_changeCount;



    static void ListChanged(object sender, EventArgs e)

    {

    s_changeCount++;

    }



    public static void Usage()

    {

    var names = new MyList<string>();

    names.Changed += new EventHandler(ListChanged);

    names.Add("Liz");

    names.Add("Martha");

    names.Add("Beth");

    Console.WriteLine(s_changeCount); // "3"

    }

    }

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

    Выражения


    Выражения создаются из операндов и операторов. Операторы в выражении указывают, какие действия нужно применить к операндам. Примеры операторов: +, -, *, / и new. Операндами могут являться литералы, поля, локальные переменные, выражения и т. п.

    Если выражение содержит несколько операторов, их приоритет определяет порядок, в котором они оцениваются. Например, выражение x + y * z вычисляется как x + (y * z), поскольку оператор * имеет более высокий приоритет, чем оператор +.

    Если операнд располагается между двумя операторами с одинаковым приоритетом, порядок их выполнения определяется ассоциативностью операторов.

    • Все бинарные операторы, за исключением операторов объединения со значением NULL и операторов присваивания, являются левоассоциативными, т. е. эти операции выполняются слева направо. Например, выражение x + y + z вычисляется как (x + y) + z.

    • Операторы присваивания, операторы объединения со значением NULL ?? и ??=, а также условный оператор ?: являются правоассоциативными, т. е. эти операции выполняются справа налево. Например, выражение x = y = z вычисляется как x = (y = z).

    Приоритет и ассоциативность операторов можно изменять, используя скобки. Например, в выражении x + y * z сначала y умножается на z, а результат прибавляется к x, а в выражении (x + y) * z сначала суммируются x и y, а результат умножается на z.

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

    C# предоставляет несколько операторов для выполнения арифметическихлогических операций, побитовых операций и сдвигов, сравнения на равенство и порядок.

    Полный список операторов C#, упорядоченных по уровню приоритета, см. в статье Операторы C#.

    Операторы


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

    • С помощью блоков можно использовать несколько операторов в таких контекстах, где ожидается только один оператор. Блок состоит из списка инструкций, заключенных между разделителями { и }.

    • Операторы объявления используются для объявления локальных переменных и констант.

    • Операторы выражений позволяют вычислять выражения. В качестве оператора можно использовать такие выражения, как вызовы методов, выделение объектов с помощью оператора new, назначения с помощью = и составных операторов присваивания, операторы ++ и -- для приращения и уменьшения, а также выражения await.

    • Операторы выбора используются для выбора одного оператора из нескольких возможных вариантов в зависимости от значения какого-либо выражения. Эта группа содержит операторы if и switch.

    • Операторы итерации используются для многократного выполнения внедренного оператора. Эта группа содержит операторы while, do, for и foreach.

    • Операторы перехода используются для передачи управления. Эта группа содержит операторы break, continue, goto, throw, return и yield.

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

    • Операторы checked и unchecked операторы позволяют управлять контекстом проверки переполнения для целочисленных арифметических операций и преобразований.

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

    • Оператор using используется для получения ресурса перед определенным оператором, и для удаления ресурса после его завершения.


    Ниже перечислены виды операторов, которые можно использовать.

    • Объявление локальной переменной.

    • Объявление локальной константы.

    • Оператор выражений.

    • Оператор if.

    • Оператор switch.

    • Оператор while.

    • Оператор do.

    • Оператор for.

    • Оператор foreach.

    • Оператор break.

    • Оператор continue.

    • Оператор goto.

    • Оператор return.

    • Оператор yield.

    • Операторы throw и try.

    • Операторы checked и unchecked.

    • Оператор lock.

    • Оператор using.


    1   2   3   4   5   6   7   8   9   10   11


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