Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Экземпляры классов в сравнении с экземплярами классовСодержание книги
Поиск на нашем сайте
Поскольку классы являются ссылочными типами, в переменной объекта класса хранится ссылка на адрес объекта в управляемой куче. Если первому объекту назначен второй объект того же типа, обе переменные ссылаются на объект, расположенный по данному адресу. Эта особенность обсуждается более подробно далее в этом разделе. Экземпляры классов создаются с помощью оператора new. В следующем примере Person является типом, а person1 и person2 — являются экземплярами или объектами этого типа.
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { public class Person { public string Name { get; set; } public int Age { get; set; } public Person(string name, int age) { Name = name; Age = age; } }
class Program { static void Main() { Person person1 = new Person("Anna", 24); Console.WriteLine("person1 Имя = {0} Возраст = {1}", person1.Name, person1.Age); Person person2 = person1; person2.Name = "John"; person2.Age = 22; Console.WriteLine("person2 Имя = {0} Возраст = {1}", person2.Name, person2.Age); Console.WriteLine("person1 Имя = {0} Возраст = {1}", person1.Name, person1.Age); Console.WriteLine("Для продолжение нажмите любую клавишу... "); Console.ReadKey(); } } } /* Выведет: * person1 Имя = Anna Возраст = 24 * person2 Имя = John Возраст = 24 * person1 Имя = John Возраст = 22 * Для продолжение нажмите любую клавишу... */
Поскольку структуры являются типами значений, в переменной объекта структуры хранится копия всего объекта. Экземпляры структур также можно создать с помощью оператора new, однако он не является обязательным.
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { public struct Person { public string Name; public int Age; public Person(string name, int age) { Name = name; Age = age; } }
public class Application { static void Main() { Person p1 = new Person("Alex", 9); Console.WriteLine("p1 Имя = {0} Возраст = {1}", p1.Name, p1.Age); Person p2 = p1; p2.Name = "Spencer"; p2.Age = 7; Console.WriteLine("p2 Имя = {0} Возраст = {1}", p2.Name, p2.Age); Console.WriteLine("p1 Имя = {0} Возраст = {1}", p1.Name, p1.Age); Console.WriteLine("Для продолжение нажмите любую клавишу..."); Console.ReadKey(); } } } /* Выведет: * p1 Имя = Alex Возраст = 9 * p2 Имя = Spencer Возраст = 7 * p1 Имя = Alex Возраст = 9 */
Идентификация и равенство значений
Сравнивая два объекта на предмет равенства, сначала необходимо определить, нужно ли узнать, представляют ли две переменные один объект в памяти или значения одного или нескольких их полей являются равными. Если планируется сравнить значения, следует решить, являются ли объекты экземплярами типов значений (структурами) или ссылочными типами (классами, делегатами, массивами).
Слегка перепишем код метода Main для классов предыдущего примера и добавим:
Person p1 = new Person("Bob The Zealot", 75); Person p2 = new Person("1", 1); p2 = p1; // Выведет: p2 и p1 имеют одинаковые значения if (p2.Equals(p1)) Console.WriteLine("p2 и p1 имеют одинаковые значения"); Console.WriteLine("Для продолжение нажмите любую клавишу... "); Console.ReadKey();
Слегка перепишем код метода Main для структур предыдущего примера и добавим:
Person p1 = new Person("Wallace", 75); Person p2; p2.Name = "Wallace"; p2.Age = 75; // Выведет: p2 и p1 имеют одинаковые значения if (p2.Equals(p1)) Console.WriteLine("p2 и p1 имеют одинаковые значения"); Console.WriteLine("Для продолжение нажмите любую клавишу..."); Console.ReadKey();
Реализация System.ValueType Equals использует отображение, поскольку необходимо определить поля, находящиеся в любой структуре. При создании собственных структур переопределите метод Equals для предоставления эффективного алгоритма равенства, соответствующего вашему типу.
Понятие «Индексатор» Понятие «Индексатор»
Понятие «Индексатор»
Индексаторы позволяют индексировать экземпляры класса или структуры так же, как массивы. Индексаторы напоминают свойства, но их методы доступа принимают параметры. В следующем примере ниже, определяется универсальный класс и в качестве средств присвоения и извлечения значений создаются простые методы доступа get и set. Класс Program создает экземпляр этого класса для хранения строк и выводит всего одну строку:
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { class SampleCollection<T> { // Объявляем массив для хранения данных элементов private T[] arr = new T[100]; // Объявляем индексатор, который позволит клиенту код // использующий [] при работе с классом public T this[int i] { get { // Этот индексатор очень прост, и просто возвращает или задает соответствующий элемент из внутреннего массива return arr[i]; } set { arr[i] = value; } } }
class Program { static void Main(string[] args) { // Объявите экземпляр SampleCollection. SampleCollection<string> stringCollection = new SampleCollection<string>(); // Используем [] конструкцию на типе stringCollection[0] = "Hello, world!"; Console.WriteLine(stringCollection[0]); Console.WriteLine("Для продолжения нажмите любую клавишу... "); Console.ReadKey(); } } }
Общие сведения об индексаторах:
Использование индексаторов
Индексаторы являются синтаксическим удобством, позволяющим создавать класс, структуру или интерфейс, доступ к которому клиентские приложения получают, как к массиву. Чаще всего индексаторы реализуются в типах, главная цель которых — инкапсуляция внутренней коллекции или массива. Например, предположим, что имеется класс с именем «TempRecord», представляющий набор температур по шкале Фаренгейта, полученных в 10 различных моментов в течение 24 часов. Класс содержит массив с именем «temps» типа float, представляющий температуры, и DateTime, представляющий дату регистрации температур. Путём внедрения в этот класс индексатора, клиенты получат доступ к температурам в экземпляре TempRecord с помощью float temp = tr[4], а не float temp = tr.temps[4]. Использование индексатора не только упрощает синтаксис для клиентских приложений, но и делает класс и его назначение интуитивно понятными для других разработчиков. Чтобы объявить, индексатор для класса или структуры, используйте ключевое слово this как показано в следующем примере:
public int this[int index] // Объявление индексатора { // get и set методы доступа }
Сигнатура индексатора состоит из количества и типов его формальных параметров. В сигнатуру не включается тип индексатора или имена формальных параметров. Если в одном классе объявлено несколько индексаторов, у них должны быть различные сигнатуры. Значение индексатора не классифицируется как переменная, поэтому не допускается передача значения индексатора как параметра ref или out. Чтобы предоставить индексатору имя, которое можно использовать в других языках, используйте в объявлении атрибут name. Пример:
[System.Runtime.CompilerServices.IndexerName("TheItem")] public int this[int index] // Объявление индексатора { // get и set методы доступа }
Этот индексатор будет иметь имя TheItem. Если атрибут имени не предоставлен, используется имя по умолчанию Item.
В следующем примере показано, как объявить закрытое поле массива temps и индексатор. Индексатор обеспечивает прямой доступ к экземпляру tempRecord[i]. В качестве альтернативы применению индексатора можно объявить массив как член типа public осуществлять прямой доступ к его членам tempRecord.temps[i]. Обратим внимание, что при вычислении доступа индексатора, например, в инструкции Console.Write вызывается метод доступа get. Таким образом, если не существует метода доступа get, происходит ошибка времени компиляции:
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { class TempRecord { // Массив температурных параметров private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F, 61.3F, 65.9F, 62.1F, 59.2F, 57.5F }; // Для клиентского код проверки входных данных при обращении к индексатору public int Length { get { return temps.Length; } } // Объявление индексатора // Если индекс находится вне диапазона, массив temps выдаст исключение public float this[int index] { get { return temps[index]; }
set { temps[index] = value; } } }
class Program { static void Main() { TempRecord tempRecord = new TempRecord(); // Используем метод доступа "set" индексатора tempRecord[3] = 58.3F; tempRecord[5] = 60.1F; // Используем метод доступа "get" индексатора for (int i = 0; i < 10; i++) { Console.WriteLine("Элемент #{0} = {1}", i, tempRecord[i]); } Console.WriteLine("Для продолжения нажмите любую клавишу... "); Console.ReadKey(); } } } /* Выведет: * Элемент #0 = 56.2 * Элемент #1 = 56.7 * Элемент #2 = 56.5 * Элемент #3 = 58.3 * Элемент #4 = 58.8 * Элемент #5 = 60.1 * Элемент #6 = 65.9 * Элемент #7 = 62.1 * Элемент #8 = 59.2 * Элемент #9 = 57.5 * Для продолжения нажмите любую клавишу... */
C# не ограничивает тип индексатора типом «integer».Например, может оказаться полезным использовании в индексаторе строки (string). Такой индексатор можно реализовать, выполнив поиск строки в коллекции и возвратив соответствующее значением. Методы доступа можно перегружать, версии типа «string» и «integer» могут сосуществовать совместно в одном пространстве имён.
В этом примере объявляется класс, в котором хранятся дни недели. Объявляется метод доступа get, который принимает строку (название дня недели) и возвращает соответствующее целое число. Например, воскресенье возвращает 0, понедельник возвращает 1 и т. д. Неверный день недели вернёт -1 и выдаст исключение (прервёт выполнение):
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { class DayCollection { string[] days = { "Пн.", "Вт.", "Ср.", "Чт.", "Пт.", "Суб.", "Вск." };
// Находим день или вернём -1 private int GetDay(string testDay) { for (int j = 0; j < days.Length; j++) { if (days[j] == testDay) { return j; } } throw new System.ArgumentOutOfRangeException(testDay, "testDay должен быть от \"Пн.\" до \"Вск.\""); } // "get" возвращает int для полученной строки public int this[string day] { get { return (GetDay(day)); } } }
class Program { static void Main(string[] args) { DayCollection week = new DayCollection(); Console.WriteLine(week["Чт."]); // Выводим ArgumentOutOfRangeException если указали неверную строку Console.WriteLine(week["Указан 8-ой день недели"]); Console.WriteLine("Для продолжения нажмите любую клавишу... "); Console.ReadKey(); } } } /* Выведет (после вывода выдаст исключение): * 5 * Для продолжения нажмите любую клавишу... */
Существуют два основных способа повышения надежности и безопасности индексаторов.
Индексаторы в интерфейсах
Индексаторы можно объявлять в интерфейсе (interface). Между методами доступа индексаторов интерфейса и методами доступа индексаторов класса существуют следующие отличия:
Поэтому метод доступа предназначен для того, чтобы указывать, доступен ли индексатор для чтения и записи, только для чтения или только для записи.
Ниже приведён пример метода доступа индексатора интерфейса:
public interface ISomeInterface { //...
// Индексатор string this[int index] { get; set; } }
Сигнатура индексатора должна отличаться от сигнатур всех других индексаторов, объявленных в том же интерфейсе.
В следующем примере показана реализация индексаторов интерфейса:
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace LC_Console { // Интерфейс public interface ISomeInterface { // Индексатор интерфейса int this[int index] { get; set; } }
// Реализация интерфейса class IndexerClass: ISomeInterface { private int[] arr = new int[100]; public int this[int index] // Объявляем индексатор { get { // Объект arr выдаст исключение IndexOutOfRange return arr[index]; } set { arr[index] = value; } } }
class Program { static void Main() { IndexerClass test = new IndexerClass(); Random rand = new Random(); // Вызываем индексатор для инициализации элементов класса test for (int i = 0; i < 10; i++) { test[i] = rand.Next(); } for (int i = 0; i < 10; i++) { Console.WriteLine("Элемент #{0} = {1}", i, test[i]); }
Console.WriteLine("Для продолжения нажмите любую клавишу... "); Console.ReadKey(); } } } /* Выведет: * Элемент #[От 0 до 9] = [Случайное число] * Для продолжения нажмите любую клавишу... */
В предыдущем примере можно использовать явную реализацию члена интерфейса с помощью полного имени члена интерфейса. Однако, полное имя требуется для исключения неоднозначности только тогда, когда класс реализует более одного интерфейса с одинаковой сигнатурой индексатора. Например, если класс Employee реализует два интерфейса ICitizen и IEmployee с одинаковой сигнатурой индексатора, требуется явная реализация члена интерфейса.
|
||||
Последнее изменение этой страницы: 2016-08-15; просмотров: 434; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.106.176 (0.007 с.) |