Текст книги "C# 4.0: полное руководство"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 61 (всего у книги 83 страниц)
Для генерирования последовательного ряда случайных чисел служит класс Random
. Такие последовательности чисел оказываются полезными в самых разных ситуациях, включая имитационное моделирование. Начало последовательности случайных чисел определяется некоторым начальным числом, которое может задаваться автоматически или указываться явным образом.
В классе Random
определяются два конструктора.
public Random()
public Random(int seed)
Первый конструктор создает объект типа Random
, использующий системное время для определения начального числа. А во втором конструкторе используется начальное значение seed, задаваемое явным образом.
Методы, определенные в классе Random, перечислены в табл. 21.14.
Таблица 21.14. Методы, определенные в классе Random
Метод – Назначение
public virtual int Next() – Возвращает следующее случайное целое число, которое будет находиться в пределах от 0 до Int32.MaxValue-1 включительно
public virtual int Next(intmaxValue) – Возвращает следующее случайное целое число, которое будет находиться в пределах от 0 до maxValue-1 включительно
public virtual int Next(intminValue,intmaxValue) – Возвращает следующее случайное целое число, которое будет находиться в пределах от minValue до maxValue-1 включительно
public virtual void NextBytes(byte[] buffer) – Заполняет массив buffer последовательностью случайных целых чисел. Каждый байт в массиве будет находиться в пределах от 0 до Byte .MaxValue-1 включительно
public virtual double NextDouble() – Возвращает из последовательности следующее случайное число, которое представлено в форме с плавающей точкой, больше или равно 0,0 и меньше 1,0
protected virtual double Sample() – Возвращает из последовательности следующее случайное число, которое представлено в форме с плавающей точкой, больше или равно 0,0 и меньше 1,0. Для получения несимметричного или специального распределения случайных чисел этот метод необходимо переопределить в производном классе
Ниже приведена программа, в которой применение класса Random демонстрируется на примере создания компьютерного варианта пары игральных костей.
// Компьютерный вариант пары игральных костей.
using System;
class RandDice {
static void Main() {
Random ran = new Random();
Console.Write(ran.Next(1, 7) + " ");
Console.WriteLine(ran.Next(1, 7));
}
}
При выполнении этой программы три раза подряд могут быть получены, например, следующие результаты.
5 2
4 4
1 6
Сначала в этой программе создается объект класса Random. А затем в ней запрашиваются два случайных значения в пределах от 1 до 6.
В классе GC инкапсулируются средства «сборки мусора». Методы, определенные в этом классе, перечислены в табл. 21.15.
Таблица 21.15. Методы, определенные в классе GC
Метод – Назначение
public static voidAddMemoryPressure(longbytesAllocated) – Задает в качестве параметра bytes Allocated количество байтов, распределенных в неуправляемой области памяти
public static void CancelFullGCNotification() – Отменяет уведомление о “сборке мусора”
public static void Collect() public static void Collect(intgeneration) – Инициализирует процесс “сборки мусора”
public static void Collect (intgeneration,GCCollectionModemode) – Инициализирует процесс “сборки мусора” в областях памяти с номерами поколений от 0 до generation
public static int CollectionCount (intgeneration) – Инициализирует процесс “сборки мусора” в областях памяти с номерами поколений от 0 до generation в'режиме, определяемом параметром mode
public static int GetGeneration (objectobj) – Возвращает количество операций “сборки мусора”, выполненных в области памяти с номером поколения generation Возвращает номером поколения для области памяти, доступной по ссылке obj
public static int GetGeneration(WeakReferencewo) – Возвращает номер поколения для области памяти, доступной по “слабой" ссылке, задаваемой параметром wo. Наличие “слабой" ссылки не защищает объект от “сборки мусора”
public static long GetTotalMemory(bool forceFullCollection) – Возвращает общий объем памяти (в байтах), выделенной на данный момент. Если параметр forceFullCollection имеет логическое значение true, то сначала выполняется “сборка мусора”
public static void KeepAlive(objectobj) Создает ссылку на объект obj, защищая его от “сборки мусора”. Действие этой ссылки оканчивается после выполнения метода KeepAlive()
public static void RegisterForFullGCNotification(intmaxGenerationThreshold,int largeObjectHeapThreshold) – Разрешает уведомление о “сборке мусора”. Значение параметра maxGenerationThreshold обозначает количество объектов второго поколения в обычной “куче", которые будут инициировать уведомление. А значение параметра largeObjectHeapThreshold обозначает количество объектов в крупной “куче", которые будут инициировать уведомление. Оба значения должны быть указаны в пределах от 1 до 99
public static void RemoveMemoryPressure(long bytesAllocated) – Задает в качестве параметра bytesAllocated количество байтов, освобождаемых в неуправляемой области памяти
public static void ReRegisterForFinalize(object obj) – Вызывает деструктор для объекта obj. Этот метод аннулирует действие метода SuppressFinalize()
public static void SuppressFinalize(objectobj) – Препятствует вызову деструктора для объекта obj
public static GCNotificationStatus WaitForFullGCApproach() – Ожидает уведомления о том, что должен произойти полный цикл “сборки мусора”. Здесь GCNotificationStatus – перечисление, определенное в пространстве имен System
public static GCNotificationStatus WaitForFullGCApproach(int millisecondsTimeout) – Ожидает уведомления о том, что долженпроизойти полный цикл “сборки мусора", в течение времени, задаваемого пара метром millisecondsTimeout. Здесь GCNotificationStatus – перечисление, определенное в пространстве имен System
public static GCNotificationStatus WaitForFullGCComplete() – Ожидает уведомления о завершении полного цикла “сборки мусора". Здесь GCNotificationStatus – перечисление, определенное в пространстве имен System
public static GCNotificationStatus WaitForFullComplete (int millisecondsTimeout) – Ожидает уведомления о завершении полного цикла «сборки мусора» в течение времени, задаваемого параметром millisecondsTimeout. Здесь GCNotificationStatus – перечисление, определенное в пространстве имен System
public static void WaitForPendingFinalizers() – Прекращает выполнение вызывающего потока до тех пор, пока не будут выполнены все вызванные и незавершенные деструкторы
Кроме того, в классе GC определяется следующее доступное только для чтения свойство:
public static int MaxGeneration { get; }
Свойство MaxGeneration
содержит максимальный номер поколения, доступный для системы. Номер поколения обозначает возраст выделенной области памяти. Чем старше выделенная область памяти, тем больше номер ее поколения. Номера поколений позволяют повысить эффективность работы системы « сборки мусора».
В большинстве приложений возможности класса GC не используются. Но в особых случаях они оказываются весьма полезными. Допустим, что требуется организовать принудительную "сборку мусора" с помощью метода Collect()
в выбранный момент времени. Как правило, «сборка мусора» происходит в моменты, не указываемые специально в программе. А поскольку для ее выполнения требуется некоторое время, то желательно, чтобы она не происходила в тот момент, когда решается критичная по времени задача. С другой стороны, «сборку мусора» и другие вспомогательные операции можно выполнить во время простоя программы. Имеется также возможность регистрировать уведомления о приближении и завершении «сборки мусора».
Для проектов с неуправляемым кодом особое значение имеют два следующих метода из класса GC: AddMemoryPressure()
и RemoveMemoryPressure()
. С их помощью указывается большой объем неуправляемой памяти, выделяемой или освобождаемой в программе. Особое значение этих методов состоит в том, что система управления памятью не контролирует область неуправляемой памяти. Если программа выделяет большой объем неуправляемой памяти, то это может сказаться на производительности, поскольку системе ничего неизвестно о таком сокращении объема свободно доступной памяти. Если же большой объем неуправляемой памяти выделяется с помощью метода AddMemoryPressure()
, то система CLR уведомляется о сокращении объема свободно доступной памяти. А если выделенная область памяти освобождается с помощью метода RemoveMemoryPressure()
, то система CLR уведомляется о соответствующем восстановлении объема свободно доступной памяти. Следует, однако, иметь в виду, что метод RemoveMemoryPressure()
необходимо вызывать только для уведомления об освобождении области неуправляемой памяти, выделенной с помощью метода AddMemoryPressure()
.
В основу типа object
в C# положен класс object
. Члены класса Object
подробно рассматривались в главе 11, но поскольку он играет главную роль в С#, то его методы ради удобства повторно перечисляются в табл. 21.16. В классе object
определен конструктор
public Object()
который создает пустой объект.
Таблица 21.16. Методы, определенные в классе Object
Метод – Назначение
public virtual bool Equals(objectobj) – Возвращает логическое значение true, если вызывающий объект оказывается таким же, как и объект, определяемый параметром obj. В противном случае возвращается значение false
public static bool Equals(object obj A,objectobjB) – Возвращает логическое значение true, если объект obj А оказывается таким же, как и объект objB. В противном случае возвращается значение false
protected Finalize() – Выполняет завершающие действия перед процессом “сборки мусора”. В C# метод Finalize() доступен через деструктор
public virtual int GetHashCode() – Возвращает хеш-код, связанный с вызывающим объектом
public Type GetType() – Получает тип объекта во время выполнения программы
protected object MemberwiseClone() – Создает “неполную” копию объекта. При этом копируются члены, но не объекты, на которые ссылаются эти члены
public static bool ReferenceEquals(objectobjA, objectobjB) – Возвращает логическое значение true, если объекты obj А и objB ссылаются на один и тот же объект. В противном случае возвращается логическое значение false
public virtual string ToString() – Возвращает строку, описывающую объект
В версии .NET Framework 4.0 внедрен удобный способ создания групп объектов (так называемых кортежей). В основу этого способа положен статический класс Tuple
, в котором определяется несколько вариантов метода Create()
для создания кортежей, а также различные обобщенные классы типа Tuple<. . . >
, в которых инкапсулируются кортежи. В качестве примера ниже приведено объявление варианта метода Create()
, возвращающего кортеж с тремя членами.
public static Tuple
Create
Следует заметить, что данный метод возвращает объект типа Tuple
, в котором инкапсулируются члены кортежа iteml, item2 и item3. Вообще говоря, кортежи оказываются полезными в том случае, если группу значений нужно интерпретировать как единое целое. В частности, кортежи можно передавать методам, возвращать из методов или же сохранять в коллекции либо в массиве.
Во многих классах приходится реализовывать интерфейс IComparable
или IComparable
, поскольку он позволяет сравнивать один объект с другим, используя различные методы, определенные в среде .NET Framework. Интерфейсы IComparable
и IComparable
были представлены в главе 18, где они использовались в примерах программ для сравнения двух объектов, определяемых параметрами обобщенного типа. Кроме того, они упоминались при рассмотрении класса Array
ранее в этой главе. Но поскольку эти интерфейсы имеют особое значение и применяются во многих случаях, то ниже приводится их краткое описание.
Интерфейс IComparable
реализуется чрезвычайно просто, потому что он состоит всего лишь из одного метода.
int CompareTo(object obj)
В этом методе значение вызывающего объекта сравнивается со значением объекта, определяемого параметром obj. Если значение вызывающего объекта больше, чем у объекта obj, то возвращается положительное значение; если оба значения равны – нулевое значение, а если значение вызывающего объекта меньше, чем у объекта obj, – отрицательное значение.
Обобщенный вариант интерфейса IComparable
объявляется следующим образом.
public interface IComparable
В данном варианте тип сравниваемых данных передается параметру Т в качестве аргумента типа. В силу этого объявление метода CompareTo()
претерпевает изменения и выглядит так, как показано ниже.
int CompareTo(Т other)
В этом объявлении тип данных, которыми оперирует метод CompareTo()
, может быть указан явным образом. Следовательно, интерфейс IComparable
обеспечивает типовую безопасность. Именно по этой причине он теперь считается более предпочтительным в программировании на С#, чем интерфейс IComparable
.
Интерфейс IEquatable
реализуется в тех классах, где требуется определить порядок сравнения двух объектов на равенство их значений. В этом интерфейсе определен только один метод, Equals()
, объявление которого приведено ниже.
bool Equals(Т other)
Этот метод возвращает логическое значение true
, если значение вызывающего объекта оказывается равным значению другого объекта other, в противном случае – логическое значение false
.
Интерфейс IEquatable
реализуется в нескольких классах и структурах среды .NET Framework, включая структуры числовых типов и класс String
. Для реализации интерфейса IEquatable
обычно требуется также переопределять методы Equals(Object)
и GetHashCode()
, определенные в классе Object
.
Интерфейс IConvertible
реализуется в структурах всех типов значений, String
и DateTime
. В нем определяются различные преобразования типов. Реализовывать этот интерфейс в создаваемых пользователем классах, как правило, не требуется.
Реализовав интерфейс ICloneable
, можно создать все условия для копирования объекта. В интерфейсе ICloneable
определен только один метод, Clone()
, объявление которого приведено ниже.
object Clone()
В этом методе создается копия вызывающего объекта, а конкретная его реализация зависит от способа создания копии объекта. Вообще говоря, существуют две разновидности копий объектов: полная и неполная. Если создается полная копия, то копия совершенно не зависит от оригинала. Так, если в исходном объекте содержится ссылка на другой объект О, то при его копировании создается также копия объекта О. А при создании неполной копии осуществляется копирование одних только членов, но не объектов, на которые эти члены ссылаются. Так, после создания неполной копии объекта, ссылающегося на другой объект О, копия и оригинал будут ссылаться на один и тот же объект О, причем любые изменения в объекте О будут оказывать влияние как на копию, так и на оригинал. Как правило, метод Clone()
реализуется для получения полной копии. А неполные копии могут быть созданы с помощью метода MemberwiseClone()
, определенного в классе Object
.
Ниже приведен пример программы, в которой демонстрируется применение интерфейса ICloneable
. В ней создается класс Test
, содержащий ссылку на объект класса X. В самом классе Test
используется метод Clone()
для создания полной копии.
// Продемонстрировать применение интерфейса ICloneable.
using System;
class X {
public int a;
public X(int x) { a = x; }
}
class Test : ICloneable {
public X o;
public int b;
public Test(int x, int y) {
o = new X(x);
b = y;
}
public void Show(string name) {
Console.Write("Значения объекта " + name + ": ");
Console.WriteLine(«o.a: {0}, b: {1}», o.a, b);
}
// Создать полную копию вызывающего объекта,
public object Clone() {
Test temp = new Test(o.a, b);
return temp;
}
}
class CloneDemo {
static void Main() {
Test ob1 = new Test(10, 20);
ob1.Show(«ob1»);
Console.WriteLine(«Сделать объект ob2 копией объекта ob1.»);
Test ob2 = (Test)ob1.Clone();
ob2.Show(«ob2»);
Console.WriteLine("Изменить значение ob1.о.а на 99, " +
« а значение ob1.b – на 88.»);
ob1.o.a = 99;
ob1.b = 88;
ob1.Show(«ob1»);
ob2.Show(«ob2»);
}
}
Ниже приведен результат выполнения этой программы.
Значения объекта оb1: о.а: 10, b: 20
Сделать объект оb2 копией объекта оb1.
Значения объекта оb2: о.а: 10, b: 20
Изменить значение ob1.о.а на 99, а значение obl.b – на 88.
Значения объекта оb1: о.а: 99, b: 88
Значения объекта оb2: о.а: 10, b: 20
Как следует из результата выполнения приведенной выше программы, объект оb2
является копией объекта оb1
, но это совершенно разные объекты. Изменения в одном из них не оказывают никакого влияния на другой. Это достигается конструированием нового объекта типа Test
, который выделяет новый объект типа X для копирования. При этом новому экземпляру объекта типа X присваивается такое же значение, как и у объекта типа X в оригинале.
Для получения неполной копии достаточно вызвать метод MemberwiseClone()
, определяемый в классе Object
из метода Clone()
. В качестве упражнения попробуйте заменить метод Clone()
в предыдущем примере программы на следующий его вариант.
// Сделать неполную копию вызывающего объекта,
public object Clone() {
Test temp = (Test) MemberwiseClone();
return temp;
}
После этого изменения результат выполнения данной программы будет выглядеть следующим образом.
Значения объекта ob1: о.а: 10, b: 20
Сделать объект оb2 копией объекта оb1.
Значения объекта оb2: о.а: 10, b: 20
Изменить значение ob1.о.а на 99, а значение obl.b – на 88.
Значения объекта ob1: о.а: 99, b:
88 Значения объекта оb2: о.а: 99, b: 20
Как видите, обе переменные экземпляра о в объектах оb1
и оb2
ссылаются на один и тот же объект типа X. Поэтому изменения в одном объекте оказывают влияние на другой. Но в то же время поля b типа int
в каждом из них разделены, поскольку типы значений недоступны по ссылке.
В интерфейсе IFormatProvider
определен единственный метод GetFormat()
, который возвращает объект, определяющий форматирование данных в удобочитаемой форме текстовой строки. Ниже приведена общая форма метода GetFormat()
:
object GetFormat(Type formatType)
где formatType – это объект, получаемый для форматирования.
Интерфейс IFormattable
поддерживает форматирование выводимых результатов в удобочитаемой форме. В нем определен следующий метод:
string ToString(string format, IFormatProvider formatProvider)
где format обозначает инструкции для форматирования, a formatProvider — поставщик формата.
–
ПРИМЕЧАНИЕ
Подробнее о форматировании речь пойдет в главе 22.
–
В версию .NET Framework 4.0 добавлены еще два интерфейса, поддерживающие шаблон наблюдателя: IObservable
и IObserver
. В шаблоне наблюдателя один класс (в роли наблюдаемого) предоставляет уведомления другому классу (в роли наблюдателя). С этой целью объект наблюдаемого класса регистрирует объект наблюдающего класса. Для регистрации наблюдателя вызывается метод Subscribe()
, который определен в интерфейсе IObservable
и которому передается объект типа IObserver
, принимающий уведомление. Для получения уведомлений можно зарегистрировать несколько наблюдателей. А для отправки уведомлений всем зарегистрированным наблюдателям применяются три метода, определенные в интерфейсе IObserver
. Так, метод OnNext()
отправляет данные наблюдателю, метод OnError()
сообщает об ошибке, а метод OnCompleted()
указывает на то, что наблюдаемый объект прекратил отправку уведомлений.
В этой главе рассматривается класс String
, положенный в основу встроенного в C# типа string
. Как известно, обработка символьных строк является неотъемлемой частью практически всех программ. Именно по этой причине в классе String
определяется обширный ряд методов, свойств и полей, обеспечивающих наиболее полное управление процессом построения символьных строк и манипулирования ими. С обработкой строк тесно связано форматирование данных в удобочитаемой форме. Используя подсистему форматирования, можно отформатировать данные всех имеющихся в C# числовых типов, а также дату, время и перечисления.