, поэтому можно читать или записывать в это свойство. Свойство
Name
, однако, создается один раз, когда создается новый экземпляр объекта свойств, после чего можно только прочитать значение
Name
. Свойства доступны, как если бы они были открытыми полями:
Properties props = new Properties("john");
props.Age = 21;
Console.WriteLine("My name is {0}, and I am {1} years old.", props.Name, props.Age);
Результатом этого кода является:
My name is john, and I am 21 years old.
Примечание. Имена свойств должны быть уникальными.
Как предполагает название, индексаторы позволяют легко индексировать атрибуты объектов. Предположим, что нам необходимо предоставить аналогичную функциональность, не создавая двух отдельных свойств. Можно проиндексировать имеющиеся поля, чтобы они были доступны с помощью некоторого ключа (ключ является значением, используемым для доступа к индексу, для массивов ключ является целым значением), или извлечь объявления двух свойств в примере выше и заменить их следующим:
public string this[string a] {
get {
if (a.Equals("Age")) return int.ToString(age);
else if (a.Equals("Name")) return name;
else {
throw new Exception("can only accept 'name' or 'age' key");
}
}
set {
if (a.Equals("Age")) age = int.Parse(value);
else {
throw new Exception(a + " is read only or does not exist");
}
}
}
Затем можно обратиться к атрибутам свойств следующим образом:
Properties props = new Properties("john");
props["Age"] = "21";
Console.WriteLine("my name is {0}, I am {1} years old.", props["Name"], props["Age"]);
В результате мы получим:
My name is john, I am 21 years old.
События
События C# предоставляют значительно более надежный и гибкий паттерн наблюдателя, чем в Java. Более того, они могут быть объявлены либо как поля, либо как свойства. Создание события является процессом из трех частей. Сначала
мы получаем делегата, а затем событие, связанное с этим делегатом, и наконец, когда происходит некоторое действие, вызывается событие.
Проиллюстрируем это, удаляя исключения из класса
Properties
и используя вместо этого события. Наиболее привлекательным свойством событий является гибкость, которая наблюдается при использовании модели делегата. По сути можно использовать любую специальную сигнатуру, которую желательно связать с событием, а затем подписчик на событие должен предоставить целевой метод, который соответствует требуемому списку параметров. Создание этой специальной сигнатуры начинается с определения делегата в коде пространства имен. Для класса
Properties
необходимо, чтобы он инициировал строковые события, аналогичные исключениям, которые необходимо порождать:
public delegate void ObservableDelegate(string message);
Затем объявляется
delegate
как поле
event
в классе:
public event ObservableDelegate ExceptionEventListener;
Наконец, переписывается реализация индексатора для активизации приемника события всякий раз, когда возникает условие исключения:
public string this[string а] {
get {
if (a.Equals("Age")) {
return int.ToString(age);
} else if (a.Equals("Name")) {
return name;
} else {
ExceptionEventListener(can only accept 'name' or 'age' key");
return null; // поток программы продолжается после того, как
// событие было инициировано, поэтому необходимо
// вернуть значение. В этом случае, так как ключ
// является недействительным (не 'name' или 'age'),
// возвращается null, указывая отсутствие значения
}
}
set {
if (a.Equals("Age") {
age = int.Parse(value);
}
else {
listener(a+ " is read only or does not exist");
}
}
}
Экземпляр делегата, связанный с приемником событий, никогда не создается. Это объясняется тем, что создание экземпляра реально происходит на клиенте, который потребляет это событие. Для клиента событие представляется как открытое поле, но не надо думать, что оно не имеет ограничений. Единственными возможными действиями по отношению к полю события являются:
□ Создание в событии новых экземпляров делегатов
□ Удаление экземпляров делегатов из события
C# использует операторы
+=
и
– =
соответственно для добавления и удаления экземпляров делегатов из событий. Оба оператора одинаковы в C# и Java. Недопустимо задавать событие, равным одному любому экземпляру делегата. Вместо этого можно добавить в событие столько делегатов, сколько понадобится. Это свободно транслируется в требуемое количество приемников событий для одного события. Пример ниже показывает, как это можно сделать: