355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Герберт Шилдт » Полное руководство. С# 4.0 » Текст книги (страница 56)
Полное руководство. С# 4.0
  • Текст добавлен: 7 октября 2016, 10:48

Текст книги "Полное руководство. С# 4.0"


Автор книги: Герберт Шилдт



сообщить о нарушении

Текущая страница: 56 (всего у книги 58 страниц)

Получить перечислитель, устанавливаемый в начало коллекции, вызвав для этой коллекции метод GetEnumerator().

Организовать цикл, в котором вызывается метод MoveNext(). Повторять цикл до тех пор, пока метод MoveNext() возвращает логическое значение true.

Получить в цикле каждый элемент коллекции с помощью свойства Current. Ниже приведен пример программы, в которой реализуется данная процедура. В этой программе используется класс ArrayList, но общие принципы циклического обращения к элементам коллекции с помощью перечислителя остаются неизменны ми для коллекций любого типа, в том числе и обобщенных. // Продемонстрировать применение перечислителя. using System; using System.Collections; class EnumeratorDemo { static void Main() { ArrayList list = new ArrayList(1); for (int i=0; i < 10; i++) list.Add(i); // Использовать перечислитель для доступа к списку. IEnumerator etr = list.GetEnumerator(); while(etr.MoveNext()) Console.Write(etr.Current + " "); Console.WriteLine(); // Повторить перечисление списка. etr.Reset(); while(etr.MoveNext()) Console.Write(etr.Current + " "); Console.WriteLine(); } } Вот к какому результату приводит выполнение этой программы. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 Вообще говоря, для циклического обращения к элементам коллекции цикл foreach оказывается более удобным, чем перечислитель. Тем не менее перечисли тель предоставляет больше возможностей для управления, поскольку его можно при желании всегда установить в исходное положение. Применение перечислителя типа IDictionaryEnumerator Если для организации коллекции в виде словаря, например типа Hashtable, реализуется необобщенный интерфейс IDictionary, то для циклического обра щения к элементам такой коллекции следует использовать перечислитель типа IDictionaryEnumerator вместо перечислителя типа IEnumerator. Интерфейс IDictionaryEnumerator наследует от интерфейса IEnumerator и имеет три допол нительных свойства. Первым из них является следующее свойство. DictionaryEntry Entry { get; } Свойство Entry позволяет получить пару "ключ-значение" из перечислителя в форме структуры DictionaryEntry. Напомним, что в структуре DictionaryEntry определяются два свойства, Key и Value, с помощью которых можно получать доступ к ключу или значению, связанному с элементом коллекции. Ниже приведены два дру гих свойства, определяемых в интерфейсе IDictionaryEnumerator. object Key { get; } object Value { get; } С помощью этих свойств осуществляется непосредственный доступ к ключу или значению. Перечислитель типа IDictionaryEnumerator используется аналогично обычному перечислителю, за исключением того, что текущее значение в данном случае получа ется с помощью свойств Entry, Key или Value, а не свойства Current. Следовательно, приобретя перечислитель типа IDictionaryEnumerator, необходимо вызвать метод MoveNext(), чтобы получить первый элемент коллекции. А для получения остальных ее элементов следует продолжить вызовы метода MoveNext(). Этот метод возвращает логическое значение false, когда в коллекции больше нет ни одного элемента. В приведенном ниже примере программы элементы коллекции типа Hashtable перечисляются с помощью перечислителя типа IDictionaryEnumerator. // Продемонстрировать применение перечислителя типа IDictionaryEnumerator. using System; using System.Collections; class IDicEnumDemo { static void Main() { // Создать хеш-таблицу. Hashtable ht = new Hashtable(); // Добавить элементы в таблицу. ht.Add("Кен", "555-7756"); ht.Add("Мэри", "555-9876"); ht.Add("Том", "555-3456"); ht.Add("Тодд", "555-3452"); // Продемонстрировать применение перечислителя. IDictionaryEnumerator etr = ht.GetEnumerator(); Console.WriteLine("Отобразить информацию с помощью свойства Entry."); while(etr.MoveNext()) Console.WriteLine(etr.Entry.Key + ": " + etr.Entry.Value); Console.WriteLine (); Console.WriteLine("Отобразить информацию " + "с помощью свойств Key и Value."); etr.Reset(); while(etr.MoveNext()) Console.WriteLine(etr.Key + ": " + etr.Value); } } Ниже приведен результат выполнения этой программы. Отобразить информацию с помощью свойства Entry. Мэри: 555-9876 Том: 555-3456 Тодд: 555-3452 Кен: 555-7756 Отобразить информацию с помощью свойств Key и Value. Мэри: 555-9876 Том: 555-3456 Тодд: 555-3452 Кен: 555-7756 Реализация интерфейсов IEnumerable и IEnumerator Как упоминалось выше, для циклического обращения к элементам коллекции за частую проще (да и лучше) организовать цикл foreach, чем пользоваться непосред ственно методами интерфейса IEnumerator. Тем не менее ясное представление о принципе действия подобных интерфейсов важно иметь по еще одной причине: если требуется создать класс, содержащий объекты, перечисляемые в цикле foreach, то в этом классе следует реализовать интерфейсы IEnumerator и IEnumerable. Иными словами, для того чтобы обратиться к объекту определяемого пользователем класса в цикле foreach, необходимо реализовать интерфейсы IEnumerator и IEnumerable в их обобщенной или необобщенной форме. Правда, сделать это будет нетрудно, по скольку оба интерфейса не очень велики. В приведенном ниже примере программы интерфейсы IEnumerator и IEnumerable реализуются в необобщенной форме, с тем чтобы перечислить содер жимое массива, инкапсулированного в классе MyClass. // Реализовать интерфейсы IEnumerable и IEnumerator. using System; using System.Collections; class MyClass : IEnumerator, IEnumerable { char[] chrs = { 'А', 'В', 'C', 'D' }; int idx = -1; // Реализовать интерфейс IEnumerable. public IEnumerator GetEnumerator() { return this; } // В следующих методах реализуется интерфейс IEnumerator // Возвратить текущий объект. public object Current { get { return chrs[idx]; } } // Перейти к следующему объекту. public bool MoveNext() { if(idx == chrs.Length-1) { Reset(); // установить перечислитель в конец return false; } idx++; return true; } // Установить перечислитель в начало. public void Reset() { idx = -1; } } class EnumeratorImplDemo { static void Main() { MyClass me = new MyClass(); // Отобразить содержимое объекта me. foreach(char ch in me) Console.Write(ch + " "); Console.WriteLine(); // Вновь отобразить содержимое объекта me. foreach(char ch in me) Console.Write(ch + " "); Console.WriteLine(); } } Эта программа дает следующий результат. А В С D А В С D В данной программе сначала создается класс MyClass, в котором инкапсулируется небольшой массив типа char, состоящий из символов А-D. Индекс этого массива хра нится в переменной idx, инициализируемой значением -1. Затем в классе MyClass ре ализуются оба интерфейса, IEnumerator и IEnumerable. Метод GetEnumerator() возвращает ссылку на перечислитель, которым в данном случае оказывается текущий объект. Свойство Current возвращает следующий символ в массиве, т.е. объект, ука зываемый по индексу idx. Метод MoveNext() перемещает индекс idx в следующее положение. Этот метод возвращает логическое значение false, если достигнут конец коллекции, в противном случае – логическое значение true. Напомним, что перечис литель оказывается неопределенным вплоть до первого вызова метода MoveNext(). Следовательно, метод MoveNext() автоматически вызывается в цикле foreach перед обращением к свойству Current. Именно поэтому первоначальное значение пере менной idx устанавливается равным -1. Оно становится равным нулю на первом шаге цикла foreach. Обобщенная реализация рассматриваемых здесь интерфейсов будет действовать по тому же самому принципу. Далее в методе Main() создается объект mc типа MyClass, и содержимое этого объекта дважды отображается в цикле foreach. Применение итераторов Как следует из предыдущих примеров, реализовать интерфейсы IEnumerator и IEnumerable нетрудно. Но еще проще воспользоваться итератором, который пред ставляет собой метод, оператор или аксессор, возвращающий по очереди члены со вокупности объектов от ее начала и до конца. Так, если некоторый массив состоит из пяти элементов, то итератор данного массива возвратит все эти элементы по очереди. Реализовав итератор, можно обращаться к объектам определяемого пользователем класса в цикле foreach. Обратимся сначала к простому примеру итератора. Приведенная ниже программа является измененной версией предыдущей программы, в которой вместо явной реали зации интерфейсов IEnumerator и IEnumerable применяется итератор. // Простой пример применения итератора. using System; using System.Collections; class MyClass { char[] chrs = { 'A', 'B', 'C', 'D' }; // Этот итератор возвращает символы из массива chrs. public IEnumerator GetEnumerator() { foreach(char ch in chrs) yield return ch; } } class ItrDemo { static void Main() { MyClass me = new MyClass(); foreach(char ch in me) Console.Write(ch + " "); Console.WriteLine(); } } При выполнении этой программы получается следующий результат. А В С D Как видите, содержимое массива mc.chrs перечислено. Рассмотрим эту программу более подробно. Во-первых, обратите внимание на то, что в классе MyClass не указывается IEnumerator в качестве реализуемого интерфей са. При создании итератора компилятор реализует этот интерфейс автоматически. И во-вторых, обратите особое внимание на метод GetEnumerator(), который ради удобства приводится ниже еще раз. // Этот итератор возвращает символы из массива chrs. public IEnumerator GetEnumerator() { foreach(char ch in chrs) yield return ch; } Это и есть итератор для объектов класса MyClass. Как видите, в нем явно реализу ется метод GetEnumerator(), определенный в интерфейсе IEnumerable. А теперь перейдем непосредственно к телу данного метода. Оно состоит из цикла foreach, в котором возвращаются элементы из массива chrs. И делается это с помощью опе ратора yield return. Этот оператор возвращает следующий объект в коллекции, которым в данном случае оказывается очередной символ в массиве chrs. Благодаря этому средству обращение к объекту mc типа MyClass организуется в цикле foreach внутри метода Main(). Обозначение yield служит в языке C# в качестве контекстного ключевого слова. Это означает, что оно имеет специальное назначение только в блоке итератора. А вне этого блока оно может быть использовано аналогично любому другому идентификатору. Следует особо подчеркнуть, что итератор не обязательно должен опираться на мас сив или коллекцию другого типа. Он должен просто возвращать следующий элемент из совокупности элементов. Это означает, что элементы могут быть построены дина мически с помощью соответствующего алгоритма. В качестве примера ниже приведе на версия предыдущей программы, в которой возвращаются все буквы английского алфавита, набранные в верхнем регистре. Вместо массива буквы формируются в цикле for. // Пример динамического построения значений, // возвращаемых по очереди с помощью итератора. using System; using System.Collections; class MyClass { char ch = 'A'; // Этот итератор возвращает буквы английского // алфавита, набранные в верхнем регистре. public IEnumerator GetEnumerator() { for(int i=0; i < 26; i++) yield return (char) (ch + i); } } class ItrDemo2 { static void Main() { MyClass me = new MyClass(); foreach(char ch in me) Console.Write(ch + " "); Console.WriteLine(); } } Вот к какому результату приводит выполнение этой программы. A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Прерывание итератора Для преждевременного прерывания итератора служит следующая форма опера тора yield. yield break; Когда этот оператор выполняется, итератор уведомляет о том, что достигнут конец коллекции. А это, по существу, останавливает сам итератор. Приведенная ниже программа является версией предыдущей программы, изме ненной с целью отобразить только первые десять букв английского алфавита. // Пример прерывания итератора. using System; using System.Collections; class MyClass { char ch = 'A'; // Этот итератор возвращает первые 10 букв английского алфавита. public IEnumerator GetEnumerator() { for(int i=0; i < 26; i++) { if(i == 10) yield break; // прервать итератор преждевременно yield return (char) (ch + i); } } } class ItrDemo3 { static void Main() { MyClass mc = new MyClass(); foreach(char ch in mc) Console.Write(ch + " "); Console.WriteLine(); } } Эта программа дает следующий результат. A B C D E F G H I J Применение нескольких операторов yield В итераторе допускается применение нескольких операторов yield. Но каждый такой оператор должен возвращать следующий элемент в коллекции. В качестве при мера рассмотрим следующую программу. // Пример применения нескольких операторов yield. using System; using System.Collections; class MyClass { // Этот итератор возвращает буквы А, В, С, D и Е. public IEnumerator GetEnumerator() { yield return 'A'; yield return 'B'; yield return 'C'; yield return 'D'; yield return 'E'; } } class ItrDemo5 { static void Main() { MyClass me = new MyClass (); foreach(char ch in mc) Console.Write(ch + " "); Console.WriteLine(); } } Ниже приведен результата выполнения этой программы. А В С D Е В данной программе внутри метода GetEnumerator() выполняются пять опера торов yield. Следует особо подчеркнуть, что они выполняются по очереди и каждый раз, когда из коллекции получается очередной элемент. Таким образом, на каждом шаге цикла foreach в методе Main() возвращается только один символ. Создание именованного итератора В приведенных выше примерах был продемонстрирован простейший способ ре ализации итератора. Но ему имеется альтернатива в виде именованного итератора. В данном случае создается метод, оператор или аксессор, возвращающий ссылку на объект типа IEnumerable. Именно этот объект используется в коде для предоставле ния итератора. Именованный итератор представляет собой метод, общая форма кото рого приведена ниже: public IEnumerable имяитератора(списокпараметров) { // ... yield return obj; } где имяитератора обозначает конкретное имя метода; списокпараметров – от нуля до нескольких параметров, передаваемых методу итератора; obj – следующий объект, возвращаемый итератором. Как только именованный итератор будет создан, его можно использовать везде, где он требуется, например для управления циклом foreach. Именованные итераторы оказываются весьма полезными в некоторых ситуациях, поскольку они позволяют передавать аргументы итератору, управляющему процес сом получения конкретных элементов из коллекции. Например, итератору можно передать начальный и конечный пределы совокупности элементов, возвращаемых из коллекции итератором. Эту форму итератора можно перегрузить, расширив ее функ циональные возможности. В приведенном ниже примере программы демонстриру ются два способа применения именованного итератора для получения элементов кол лекции. В одном случае элементы перечисляются в заданных начальном и конечном пределах, а в другом – элементы перечисляются с начала последовательности и до указанного конечного предела. // Использовать именованные итераторы. using System; using System.Collections; class MyClass { char ch = 'A'; // Этот итератор возвращает буквы английского алфавита, // начиная с буквы А и кончая указанным конечным пределом. public IEnumerable MyItr(int end) { for(int i=0; i < end; i++) yield return (char) (ch + i); } // Этот итератор возвращает буквы в заданных пределах. public IEnumerable MyItr(int begin, int end) { for(int i=begin; i < end; i++) yield return (char) (ch + i); } } class ItrDemo4 { static void Main() { MyClass mc = new MyClass(); Console.WriteLine(«Возвратить по очереди первые 7 букв:»); foreach(char ch in mc.MyItr(7)) Console.Write(ch + " "); Console.WriteLine(«n»); Console.WriteLine(«Возвратить по очереди буквы от F до L:»); foreach(char ch in mc.MyItr(5, 12)) Console.Write(ch + " "); Console.WriteLine(); } } Эта программа дает следующий результат. Возвратить по очереди первые 7 букв: А В С D Е F G Возвратить по очереди буквы от F до L: F G Н I J К L Создание обобщенного итератора В приведенных выше примерах применялись необобщенные итераторы, но, конеч но, ничто не мешает создать обобщенные итераторы. Для этого достаточно возвратить объект обобщенного типа IEnumerator или IEnumerable. Ниже приведен пример создания обобщенного итератора. // Простой пример обобщенного итератора. using System; using System.Collections.Generic; class MyClass { T[] array; public MyClass(T[] a) { array = a; } // Этот итератор возвращает символы из массива chrs. public IEnumerator GetEnumerator() { foreach(T obj in array) yield return obj; } } class GenericItrDemo { static void Main() { int[] nums = { 4, 3, 6, 4, 7, 9 }; MyClass me = new MyClass(nums); foreach(int x in mc) Console.Write(x + " "); Console.WriteLine(); bool[] bVals = { true, true, false, true }; MyClass mc2 = new MyClass(bVals); foreach(bool b in mc2) Console.Write(b + " "); Console.WriteLine(); } } Вот к какому результату приводит выполнение этой программы. 4 3 6 4 7 9 True True False True В данном примере массив, состоящий из возвращаемых по очереди объектов, пере дается конструктору класса MyClass. Тип этого массива указывает в качестве аргумен та типа в конструкторе класса MyClass. Метод GetEnumerator() оперирует данными обобщенного типа т и возвраща ет перечислитель типа IEnumerator. Следовательно, итератор, определенный в классе MyClass, способен перечислять данные любого типа. Инициализаторы коллекций В C# имеется специальное средство, называемое инициализатором коллекции и упро щающее инициализацию некоторых коллекций. Вместо того чтобы явно вызывать ме тод Add(), при создании коллекции можно указать список инициализаторов. После этого компилятор организует автоматические вызовы метода Add(), используя значе ния из этого списка. Синтаксис в данном случае ничем не отличается от инициализа ции массива. Обратимся к следующему примеру, в котором создается коллекция типа List, инициализируемая символами С, А, Е, В, D и F. List lst = new List() { 'С', 'А', 'Е', 'В', 'D', 'F' }; После выполнения этого оператора значение свойства lst.Count будет равно 6, поскольку именно таково число инициализаторов. А после выполнения следующего цикла foreach: foreach(ch in lst) Console.Write(ch + " "); получится такой результат: С A E В D F Для инициализации коллекции типа LinkedList, в которой хра нятся пары «ключ-значение», инициализаторы приходится предоставлять парами, как показано ниже. SortedList lst = new SortedList() { {1, «один»}, {2, «два» }, {3, «три»} }; Компилятор передаст каждую группу значений в качестве аргументов методу Add(). Следовательно, первая пара инициализаторов преобразуется компилятором в вызов Add(1, «один»). Компилятор вызывает метод Add() автоматически для ввода инициализаторов в коллекцию, и поэтому инициализаторы коллекций можно использовать только в кол лекциях, поддерживающих открытую реализацию метода Add(). Это означает, что инициализаторы коллекций нельзя использовать в коллекциях типа Stack, Stack, Queue или Queue, поскольку в них метод Add() не поддерживается. Их нельзя применять также в тех коллекциях типа LinkedList, где метод Add() предостав ляется как результат явной реализации соответствующего интерфейса.

ГЛАВА 26. Сетевые средства подключения к Интернету

Я зык С# предназначен для программирования в совре менной вычислительной среде, где Интернету, есте ственно, принадлежит весьма важная роль. Одной из главных целей разработки С# было внедрение в этот язык программирования средств, необходимых для до ступа к Интернету. Такой доступ можно было осуществить и в предыдущих версиях языков программирования, вклю чая С и C++, но поддержка операций на стороне сервера, загрузка файлов и получение сетевых ресурсов в этих язы ках не вполне отвечали потребностям большинства про граммистов. Эта ситуация коренным образом изменилась в С#. Используя стандартные средства C# и среды .NET Framework, можно довольно легко сделать приложения совместимыми с Интернетом и написать другие виды про грамм, ориентированных на подключение к Интернету. Поддержка сетевого подключения осуществляется через несколько пространств имен, определенных в среде .NET Framework, и главным среди них является пространство имен System.Net. В нем определяется целый ряд высо коуровневых, но простых в использовании классов, поддер живающих различные виды операций, характерных для работы с Интернетом. Для этих целей доступен также ряд пространств, вложенных в пространство имен System.Net. Например, средства низкоуровневого сетевого управления через сокеты находятся в пространстве имен System.Net. Sockets, поддержка электронной почты – в простран стве имен System.Net.Mail, а поддержка защищенных сетевых потоков – в пространстве имен System.Net. Security. Дополнительные функциональные возможно сти предоставляются в ряде других вложенных пространств имен. К числу других не менее важных пространств имен, 26 связанных с сетевым подключением к Интернету, относится пространство System. Web. Это и вложенные в него пространства имен поддерживают сетевые приложения на основе технологии ASP.NET. В среде .NET Framework имеется достаточно гибких средств и возможностей для се тевого подключения к Интернету. Тем не менее для разработки многих приложений более предпочтительными оказываются функциональные возможности, доступные в пространстве имен System.Net. Они и удобны, и просты в использовании. Именно по этому пространству имен System.Net будет уделено основное внимание в этой главе. Члены пространства имен System.Net

Пространство имен System.Net довольно обширно и состоит из многих членов. Полное их описание и обсуждение всех аспектов программирования для Интернета выходит далеко за рамки этой главы. (На самом деле для подробного рассмотрения всех вопросов, связанных с сетевым подключением к Интернету и его поддержкой в С#, потребуется отдельная книга.) Однако целесообразно хотя бы перечислить члены пространства имен System.Net, чтобы дать какое-то представление о том, что именно доступно для использования в этом пространстве. Ниже перечислены классы, определенные в пространстве имен System.Net. AuthenticationManager Authorization Cookie CookieCollection CookieContainer CookieException CredentialCache Dns DnsEndPoint DnsPermission DnsPermissionAttribute DownloadDataCompletedEventArgs DownloadProgressChangedEventArgs DownloadstringCompletedEventArgs EndPoint EndpointPermission FileWebRequest FileWebResponse FtpWebRequest FtpWebResponse HttpListener HttpListenerBasicIdentity HttpListenerContext HttpListenerException HttpListenerPrefixCollection HttpListenerRequest HttpListenerResponse HttpVersion HttpWebRequest HttpWebResponse IPAddress IPEndPoint IPEndPointCollection IPHostEntry IrDAEndPoint NetworkCredential OpenReadCompletedEventArgs OpenWriteCompletedEventArgs ProtocolViolationException ServicePoint ServicePointManager SocketAddress SocketPermission SocketPermissionAttribute TransportContext UploadDataCompletedEventArgs UploadFileCompletedEventArgs UploadProgressChangedEventArgs UploadstringCompletedEventArgs UploadValuesCompletedEventArgs WebClient WebException WebHeaderCollection WebPermission Помимо этого, в пространстве имен System.Net определен ряд делегатов. Несмотря на то что в пространстве имен System.Net определено немало членов, лишь немногие из них на самом деле требуются при решении наиболее типичных задач программирования для Интернета. Основу сетевых программных средств составляют аб страктные классы WebRequest и WebResponse. От этих классов наследуют все классы, поддерживающие конкретные сетевые протоколы. (Протокол определяет правила пере дачи данных по сети.) Например, к производным классам, поддерживающим стандарт ный сетевой протокол HTTP, относятся классы HttpWebRequest и HttpWebResponse. Классы HttpWebRequest и HttpWebResponse довольно просты в использовании. Тем не менее решение некоторых задач можно еще больше упростить, применяя под ход, основанный на классе WebClient. Так, если требуется только загрузить или вы грузить файл, то для этой цели лучше всего подойдет класс WebClient. Универсальные идентификаторы ресурсов В основу программирования для Интернета положено понятие универсального иден тификатора ресурса (URI), иногда еще называемого унифицированным указателем инфор мационного ресурса (URL). Этот идентификатор описывает местоположение ресурса в сети. В корпорации Microsoft принято пользоваться сокращением URI при описании членов пространства имен System.Net, и поэтому в данной книге выбрано именно это сокращение для обозначения универсального идентификатора ресурса. Иденти фикаторы URI, без сомнения, известны каждому, кто хотя бы раз пользовался браузе ром для поиска информации в Интернете. По существу, это адрес информационного ресурса, который указывается в соответствующем поле окна браузера. Ниже приведена общая форма идентификатора URI: Протокол://Идентификационныйномерсервера/Путькфайлу?Запрос где Протокол – это применяемый протокол, например HTTP; Идентификацион ныйномерсервера – конкретный сервер, например mhprofessional.com или WebPermissionAttribute WebProxy WebRequest WebRequestMethods WebRequestMethods.File WebRequestMethods.Ftp WebRequestMethods.Http WebResponse WebUtility Кроме того, в пространстве имен System.Net определены перечисленные ниже интерфейсы. AuthenticationModule IcertificatePolicy ICredentialPolicy ICredentials IcredentialsByHost IWebProxy IWebProxyScript IWebRequestCreate В этом пространстве имен определяются также приведенные ниже перечисления. AuthenticationSchemes DecompressionMethods FtpStatusCode HttpRequestHeader HttpResponseHeader HttpStatusCode NetworkAccess SecurityProtocolType TransportType WebExceptionStatus HerbSchildt.com; Путькфайлу – путь к конкретному файлу. Если же Путьк файлу не указан, то получается страница, доступная на указанном сервере по умолча нию. И наконец, Запрос обозначает информацию, отправляемую на сервер. Указывать Запрос необязательно. В C# идентификаторы URI инкапсулированы в класс Uri, рас сматриваемый далее в этой главе. Основы организации доступа к Интернету В классах, находящихся в пространстве имен System.Net, поддерживается модель взаимодействия с Интернетом по принципу запроса и ответа. При таком подходе пользовательская программа, являющаяся клиентом, запрашивает информацию у сервера, а затем переходит в состояние ожидания ответа. Например, в качестве запроса программа может отправить на сервер идентификатор URI некоторого веб-сайта. В от вет она получит гипертекстовую страницу, соответствующую указанному идентифи катору URI. Такой принцип запроса и ответа удобен и прост в применении, поскольку большинство деталей сетевого взаимодействия реализуются автоматически. На вершине иерархии сетевых классов находятся классы WebRequest и WebResponse, реализующие так называемые подключаемые протоколы. Как должно быть известно большинству читателей, для передачи данных в сети применяется не сколько разнотипных протоколов. К числу наиболее распространенных в Интернете относятся протокол передачи гипертекстовых файлов (HTTP), а также протокол пере дачи файлов (FTP). При создании идентификатора URI его префикс обозначает приме няемый сетевой протокол. Например, в идентификаторе http://www.HerbSchildt. com используется префикс http, обозначающий протокол передачи гипертекстовых файлов (HTTP). Как упоминалось выше, классы WebRequest и WebResponse являются абстракт ными, а следовательно, в них определенны в самом общем виде операции запроса и ответа, типичные для всех протоколов. От этих классов наследуют более конкретные производные классы, в которых реализуются отдельные протоколы. Эти производные классы регистрируются самостоятельно, используя для этой цели статический метод RegisterPrefix(), определенный в классе WebRequest. При создании объекта типа WebRequest автоматически используется протокол, указываемый в префиксе URI, если, конечно, он доступен. Преимущество такого принципа «подключения» протоко лов заключается в том, что большая часть кода пользовательской программы остается без изменения независимо от типа применяемого протокола. В среде выполнения .NET Runtime протоколы HTTP, HTTPS и FTP определяются ав томатически. Так, если указать идентификатор URI с префиксом HTTP, то будет авто матически получен HTTP-совместимый класс, который поддерживает протокол HTTP. А если указать идентификатор URI с префиксом FTP, то будет автоматически получен FTP-совместимый класс, поддерживающий протокол FTP. При сетевом подключении к Интернету чаще всего применяется протокол HTTP, поэтому именно он и рассматривается главным образом в этой главе. (Тем не менее аналогичные приемы распространяются и на все остальные поддерживаемые протоко лы.) Протокол HTTP поддерживается в классах HttpWebRequest и HttpWebResponse. Эти классы наследуют от классов WebRequest и WebResponse, а кроме того, име ют собственные дополнительные члены, применимые непосредственно к протоколу HTTP. В пространстве имен System.Net поддерживается как синхронная, так и асинхрон ная передача данных. В Интернете предпочтение чаще всего отдается синхронным транзакциям, поскольку ими легче пользоваться. При синхронной передаче данных пользовательская программа посылает запрос и затем ожидает ответа от сервера. Но для некоторых разновидностей высокопроизводительных приложений более подхо дящей оказывается асинхронная передача данных. При таком способе передачи дан ных пользовательская программа продолжает обработку данных, ожидая ответа на переданный запрос. Но организовать асинхронную передачу данных труднее. Кроме того, не во всех программах можно извлечь выгоды из асинхронной передачи данных. Например, когда требуется получить информацию из Интернета, то зачастую ниче го другого не остается, как ожидать ее. В подобных случаях потенциал асинхронной передачи данных используется не полностью. Вследствие того что синхронный доступ к Интернету реализуется проще и намного чаще, именно он и будет рассматриваться в этой главе. Далее речь пойдет прежде всего о классах WebRequest и WebResponse, поскольку именно они положены в основу сетевых программных средств, доступных в простран стве имен System.Net. Класс WebRequest Класс WebRequest управляет сетевым запросом. Он является абстрактным, по скольку в нем не реализуется конкретный протокол. Тем не менее в нем определяются те методы и свойства, которые являются общими для всех сетевых запросов. В табл. 26.1 сведены методы, определенные в классе WebRequest и поддерживающие синхронную передачу данных, а в табл. 26.2 – свойства, объявляемые в классе WebRequest. Уста навливаемые по умолчанию значения свойств задаются в производных классах. Откры тые конструкторы в классе WebRequest не определены. Для того чтобы отправить запрос по адресу URI, необходимо сначала создать объект класса, производного от класса WebRequest и реализующего требуемый про токол. С этой целью вызывается статический метод Create(), определенный в клас се WebRequest. Метод Create() возвращает объект класса, наследующего от класса WebRequest и реализующего конкретный протокол. Таблица 26.1. Методы, определенные в классе WebRequest Метод Описание public static WebRequest Create(string requestUriString) Создает объект типа WebRequest для иден тификатора URI, указываемого в строке requestUriString. Возвращаемый объект реализует протокол, заданный префиксом иден тификатора URI. Следовательно, возвращаемый объект будет экземпляром класса, производного от класса WebRequest. Если затребованный про токол недоступен, то генерируется исключение NotSupportedException. А если недействите лен указанный формат идентификатора URI, то ге нерируется исключение UriFormatException Окончание табл. 26.1 Таблица 26.2. Свойства, определенные в классе WebRequest Метод Описание public static WebRequest Create(Uri requestUri) Создает объект типа WebRequest для иденти фикатора URI, указываемого с помощью пара метра requestUri. Возвращаемый объект реализует протокол, заданный префиксом иден тификатора URI. Следовательно, возвращаемый объект будет экземпляром класса, производного от класса WebRequest. Если затребованный про токол недоступен, то генерируется исключение NotSupportedException public virtual Stream GetRequestStream() Возвращает поток вывода, связанный с запрошен ным ранее идентификатором URI public virtual WebResponse GetResponse() Отправляет предварительно сформированный за прос и ожидает ответа. Получив ответ, возвращает его в виде объекта класса WebReponse. Этот объ ект используется затем в программе для получения информации по указанному адресу URI Свойство Описание public AuthenticationLevel AuthenticationLevel{ get; set; } Получает или устанавливает уровень аутентифи кации public virtual RequestCachePolicy CachePolicy { get; set; } Получает или устанавливает правила использо вания кеша, определяющие момент получения ответа из кеша public virtual string ConnectionGroupName { get; set; } Получает или устанавливает имя группы подклю чения. Группы подключения представляют собой способ создания ряда запросов. Они не нужны для простых транзакций в Интернете public virtual long ContentLength { get; set; } Получает или устанавливает длину передаваемо го содержимого public virtual string ContentType { get; set; } Получает или устанавливает описание переда ваемого содержимого public virtual Icredentials Credentials { get; set; } Получает или устанавливает мандат, т.е. учетные данные пользователя public static RequestCachePolicy DefaultCachePolicy { get; set; } Получает или устанавливает правила использо вания кеша по умолчанию, определяющие мо мент получения ответа из кеша public static IWebProxy DefaultWebProxy { get; set; } Получает или устанавливает используемый по умолчанию прокси-сервер public virtual WebHeaderCollection Headers{ get; set; } Получает или устанавливает коллегию заголовков public TokenImpersonationLevel ImpersonationLevel { get; set; } Получает или устанавливает уровень анонимно го воплощения Класс WebResponse В классе WebResponse инкапсулируется ответ, получаемый по запросу. Этот класс является абстрактным. В наследующих от него классах создаются отдельные его вер сии, поддерживающие конкретный протокол. Объект класса WebResponse обыч но получается в результате вызова метода GetResponse(), определенного в классе WebRequest. Этот объект будет экземпляром отдельного класса, производного от класса WebResponse и реализующего конкретный протокол. Методы, определенные в классе WebResponse, сведены в табл. 26.3, а свойства, объявляемые в этом классе, – в табл. 26.4. Значения этих свойств устанавливаются на основании каждого запроса в отдельности. Открытые конструкторы в классе WebResponse не определяются. Таблица 26.3. Наиболее часто используемые методы, определенные в классе WebResponse Метод Описание public virtual void Close() Закрывает ответный поток. Закрывает также поток ввода ответа, возвращаемый методом GetResponseStream() public virtual Stream GetResponseStream() Возвращает поток ввода, связанный с запрашивае мым URI. Из этого потока могут быть введены дан ные из запрашиваемого URI Окончание табл. 26.2 Свойство Описание public virtual string Method { get; set; } Получает или устанавливает протокол public virtual bool PreAuthenticate { get; set; } Если принимает логическое значение true, то в отправляемый запрос включается информация для аутентификации. А если принимает логиче ское значение false, то информация для аутен тификации предоставляется только по требова нию адресата URI public virtual IWebProxy Proxy { get; set; } Получает или устанавливает прокси-сервер. При менимо только в тех средах, где используется прокси-сервер public virtual Uri RequestUri { get; } Получает идентификатор URI конкретного запроса public virtual int Timeout { get; set; } Получает или устанавливает количество милли секунд, в течение которых будет ожидаться ответ на запрос. Для установки бесконечного ожида ния используется значение Timeout.Infinite public virtual bool UseDefaultCredential { get; set; } Получает или устанавливает значение, которое определяет, используется ли для аутентификации устанавливаемый по умолчанию мандат. Если имеет логическое значение true, то использу ется устанавливаемый по умолчанию мандат, т.е. учетные данные пользователя, в противном случае этот мандат не используется Классы HttpWebRequest и HttpWebResponse Оба класса, HttpWebRequest и HttpWebResponse, наследуют от классов WebRequest и WebResponse и реализуют протокол HTTP. В ходе этого процесса в обоих классах вводится ряд дополнительных свойств, предоставляющих подробные сведения о транзакции по протоколу HTTP. О некоторых из этих свойств речь пойдет далее в настоящей главе. Но для выполнения простых операций в Интернете эти до полнительные свойства, как правило, не требуются. Первый простой пример Доступ к Интернету организуется на основе классов WebRequest и WebResponse. Поэтому, прежде чем рассматривать этот процесс более подробно, было бы полезно обратиться к простому примеру, демонстрирующему порядок доступа к Интернету по принципу запроса и ответа. Глядя на то, как эти классы применяются на практике, легче понять, почему они организованы именно так, а не как-то иначе. В приведенном ниже примере программы демонстрируется простая, но весьма типичная для Интернета операция получения гипертекстового содержимого из кон кретного веб-сайта. В данном случае содержимое получается из веб-сайта издатель ства McGraw-Hill по адресу www.McGraw-Hill.com, но вместо него можно подставить адрес любого другого веб-сайта. В этой программе гипертекстовое содержимое выво дится на экран монитора отдельными порциями по 400 символов, чтобы полученную информацию можно было просматривать, не прибегая к прокрутке экрана. // Пример доступа к веб-сайту. using System; Таблица 26.4. Свойства, определенные в классе WebResponse Свойство Описание public virtual long ContentLength { get; set; } Получает или устанавливает длину принимаемого со держимого. Устанавливается равным -1, если дан ные о длине содержимого недоступны public virtual string ContentType { get; set; } Получает или устанавливает описание принимаемого содержимого public virtual WebHeaderCollection Headers { get; } Получает или устанавливает коллекцию заголовков, связанных с URI public virtual bool IsFromCache { get; } Принимает логическое значение true, если запрос получен из кэша. А если запрос доставлен по сети, то принимает логическое значение false public virtual bool IsMutuallyAuthenticated { get; } Принимает логическое значение true, если клиент и сервер опознают друг друга, а иначе – принимает логическое значение false public virtual Uri ResponseUri { get; } Получает URI, по которому был сформирован ответ. Этот идентификатор может отличаться от запрашивае мого, если ответ был переадресован по другому URI using System.Net; using System.IO; class NetDemo { static void Main() { int ch; // Сначала создать объект запроса типа WebRequest по указанному URI. HttpWebRequest req = (HttpWebRequest) WebRequest.Create(«http://www.McGraw-Hill.com»); // Затем отправить сформированный запрос и получить на него ответ. HttpWebResponse resp = (HttpWebResponse) req.GetResponse(); // Получить из ответа поток ввода. Stream istrm = resp.GetResponseStream(); / А теперь прочитать и отобразить гипертекстовое содержимое, полученное по указанному URI. Это содержимое выводится на экран отдельными порциями по 400 символов. После каждой такой порции следует нажать клавишу , чтобы вывести на экран следующую порцию из 400 символов. / for(int i=1; ; i++) { ch = istrm.ReadByte (); if(ch == -1) break; Console.Write((char) ch); if((i%400)==0) { Console.Write(«nНажмите клавишу .»); Console.ReadLine(); } } // Закрыть ответный поток. При этом закрывается также поток ввода istrm. resp.Close(); } } Ниже приведена первая часть получаемого результата. (Разумеется, это содержи мое может со временем измениться в связи с обновлением запрашиваемого веб-сайта, и поэтому у вас оно может оказаться несколько иным.)


    Ваша оценка произведения:

Популярные книги за неделю