- •1. Язык программирования c# 3
- •2. Базовые элементы .Net Framework 67
- •3. ТЕхнология .Net Remoting 144
- •Введение
- •1. Язык программирования c#
- •1.1. Платформа .Net – обзор архитектуры
- •1.2. Язык c# - общие концепции синтаксиса
- •1.3. Система типов языка c#
- •1.4. Преобразования типов
- •1.5. Идентификаторы, ключевые слова и литералы
- •1.6. Объявление переменных, полей и констант
- •1.7. Выражения и операции
- •1.8. Операторы языка c#
- •1.9. Объявление и вызов методов
- •1.10. Массивы в c#
- •1.11. Работа с символами и строками в c#
- •1.12. Синтаксис объявления класса, Поля и методы класса
- •1.13. Свойства и индексаторы
- •1.14. Конструкторы класса и Жизненный цикл объекта
- •1.15. Наследование классов
- •1.16. Перегрузка операЦий
- •1.17. Делегаты
- •1.18. События
- •1.19. Интерфейсы
- •1.20. Структуры и перечисления
- •1.21. Пространства имен
- •1.22. Генерация и обработка исключительных ситуаций
- •1.23. Нововведения в языке c# 2.0
- •1.24. Обобщенные типы (generics)
- •2. Базовые элементы .Net Framework
- •2.1. Метаданные и механизм отражения
- •2.2. Пользовательские и встроенные атрибуты
- •2.3. Пространство имен system.Collections
- •2.4. Работа с файлами и директориями
- •2.5. Использование потоков данных
- •2.6. Сериализация
- •2.7. Сериализация объектов в нестандартном формате
- •2.8. Введение в xml
- •2.9. Работа с xml-документами в .Net framework
- •2.10. МНогопоточное программирование
- •2.11. Синхронизация потоков
- •2.12. Асинхронный вызов методов
- •2.13. Состав и взаимодействие сборок
- •2.14. Конфигурирование сборок
- •3. ТЕхнология .Net Remoting
- •3.1. Домены приложений
- •3.2. Архитектура .Net Remoting
- •3.3. Активация удаленных объектов и их время жизни
- •3.4. Программная настройка Remoting
- •3.5. Удаленные Объекты с клиентской активацией
- •3.6. Настройка Remoting при помощи конфигурационных файлов
- •3.7. Хостинг распределенных приложений
- •3.8. Объекты-сообщения
- •3.9. Пользовательские канальные приемники
- •4.1. Архитектура ado.Net
- •4.2. Учебная база cd Rent
- •4.3. Соединение с базой данных
- •4.4. Выполнение команд и запросов к базе данных
- •4.5. Чтение данных и объект DataReader
- •4.6. Параметризированные запросы
- •4.7. Рассоединенный набор данных
- •4.8. Заполнение Рассоединенного набора данных
- •4.9. Объект класса DataColumn – колонка таблицы
- •4.10. Объекты класса DataRow – строки таблицы
- •4.11. Работа с объектом класса DataTable
- •4.12. DataSet и схема рассоединенного набора данных
- •4.13. Типизированные DataSet
- •4.14. Поиск и фильтрация данных в DataSet
- •4.15. Класс DataView
- •4.16. СиНхронизация набора данных и базы
- •5.1. Архитектура и общие концепции asp.Net
- •5.2. Пример aspx-страницы. Структура страницы
- •5.3. Директивы страницы
- •5.4. Класс System.Web.Ui.Page. События страницы
- •5.5. Серверные элементы управления
- •5.6. Элементы управления Web Controls
- •5.7. Проверочные элементы управления
- •5.8. Списковые элементы управления
- •5.9. Связывание данных
- •5.11. Управление состояниями в web-приложениях
- •5.12. Кэширование
- •5.13. Безопасность в web-приложениях
- •5.14. Создание пользовательских элементов управления
- •Литература
2.5. Использование потоков данных
Для поддержки операций, связанных с вводом и выводом информации, библиотека классов платформы .NET предоставляет пространство имен System.IO. Основное понятие, связанное с элементами данного пространства имен, – это поток. Поток – абстрактное представление данных в виде последовательности байт. Потоки (в отличие от файлов) могут быть ассоциированы с файлами на диске, памятью, сетью. В пространстве имен System.IO поток представлен абстрактным классом Stream. От данного абстрактного класса порождены классы System.IO.FileStream (работа с файлами как с потоками), System.IO.MemoryStream (поток в памяти), System.Net.Sockets.NetworkStream (работа с сокетами как с потоками), System.Security.Cryptography.CryptoStream (потоки зашифрованных данных).
Рассмотрим основные методы и свойства класса Stream. Свойства для чтения CanRead, CanWrite и CanSeek определяют, поддерживает ли поток чтение, запись и поиск. Если поток поддерживает поиск, перемещаться по потоку можно при помощи метода Seek(). На текущую позицию в потоке указывает свойство Position (нумерация с нуля). Свойство Length возвращает длину потока, которая может быть установлена при помощи метода SetLength(). Методы Read() и ReadByte(), Write() и WriteByte() служат для чтения и записи блока байт или одиночного байта. Метод Flush() записывает данные из буфера в связанный с потоком источник данных. При помощи метода Close() поток закрывается и все связанные с ним ресурсы освобождаются.
Класс Stream вводит поддержку асинхронного ввода/вывода. Для этого служат методы BeginRead() и BeginWrite(). Уведомление о завершении асинхронной операции возможно двумя способами: или при помощи делегата тип System.AsyncCallback, передаваемого как параметр методов BeginRead() и BeginWrite(), или при помощи вызова методов EndRead() и EndWrite(), которые приостанавливают текущий поток управления до окончания асинхронной операции.
Использование методов и свойств класса Stream продемонстрируем в фрагменте кода с классом FileStream. Объект класса FileStream возвращается некоторыми методами классов FileInfo и File, кроме этого, данный объект можно создать при помощи конструктора с параметрами, включающими имя файла и режимы доступа к файлу.
// Создаем файл test.dat в текущем каталоге
FileStream fs = new FileStream("test.dat",
FileMode.OpenOrCreate,
FileAccess.ReadWrite);
// В цикле записываем туда 100 байт
for (byte i = 0; i < 100; i++) {
fs.WriteByte(i);
}
// Мы можем записывать информацию из массива байт
byte[] info = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// Первый параметр – массив, второй – смещение в массиве,
// третий – количество записываемых байт
fs.Write(info, 2, 4);
// Возвращаемся на начало файла
fs.Position = 0;
// Читаем все байты и выводим на экран
while (fs.Position <= fs.Length - 1) {
Console.Write(fs.ReadByte());
}
// Закрываем поток (и файл), освобождая ресурсы
fs.Close();
Класс MemoryStream предоставляет возможность организовать поток в оперативной памяти. Свойство Capacity этого класса позволяет получить или установить количество байтов, выделенных под поток. Метод ToArray() записывает все содержимое потока в массив байт. Метод WriteTo() переносит содержимое потока в памяти в другой поток, производный от класса Stream.
Классы-потоки представляют поток как последовательность неформатированных байт. Однако в большинстве приложений удобнее читать и записывать в поток данные примитивных типов или строк. Библиотека классов .NET Framework содержит набор парных классов вида XXXReader/XXXWriter, которые инакапсулируют поток и предоставляют к нему высокоуровневый доступ.
Классы BinaryReader и BinaryWriter позволяют при помощи своих методов читать и записывать в поток данные примитивных типов, строк и массивов байт или символов. Вся информация записывается в поток как последовательность байт. Рассмотрим работу с данными классами на следующем примере. Пусть имеется класс, который хранит информацию о студенте:
class Student {
public string Name;
public int Age;
public double MeanScore;
}
Методы, которые осуществляют запись и чтение объекта этого класса в поток в виде последовательности байт, могут иметь следующий вид:
void SaveToStream(Stream stm, Student s) {
// Конструктор класса позволяет "обернуть"
// BinaryWriter вокруг потока
BinaryWriter bw = new BinaryWriter(stm);
// BinaryWriter содержит 18 перегруженных версий
// метода Write()
bw.Write(s.Name);
bw.Write(s.Age);
bw.Write(s.MeanScore);
// Убеждаемся, что буфер BinaryWriter пуст
bw.Flush();
}
void ReadFromStream(Stream stm, Student s) {
BinaryReader br = new BinaryReader(stm);
// Для чтения каждого примитивного типа есть свой метод
s.Name = br.ReadString();
s.Age = br.ReadInt32();
s.MeanScore = br.ReadDouble();
}
Абстрактные классы TextReader и TextWriter позволяю читать и записывать данные в поток как последовательность символов. От этих классов наследуются классы StreamReader и StreamWriter. Перепишем методы для сохранения данных класса Student с использованием StreamReader и StreamWriter:
void SaveToStream(Stream stm, Student s) {
StreamWriter sw = new StreamWriter(stm);
// Запись напоминает вывод на консоль
sw.WriteLine(s.Name);
sw.WriteLine(s.Age);
sw.WriteLine(s.MeanScore);
sw.Flush();
}
void ReadFromStream(Stream stm, Student s) {
StreamReader sr = new StreamReader(stm);
// Читаем данные как строки, требуется их преобразовать
s.Name = sr.ReadLine();
s.Age = Int32.Parse(sr.ReadLine());
s.MeanScore = Double.Parse(sr.ReadLine());
}
Классы StringReader и StringWriter – это наследники классов TextReader и TextWriter, которые представляют доступ к строке или к объекту класса StringBuilder как к потоку. Это может оказаться полезным, если текстовая информация добавляется в специальный буфер в оперативной информации. Работу с данными классами иллюстрирует следующий пример:
StringWriter sw = new StringWriter();
// Пишем информацию в поток
sw.WriteLine("Hello!");
sw.WriteLine("This is an example...");
sw.Close();
// Выводим все информацию
Console.WriteLine(sw.ToString());
string s = "Big\n Big string\n 10";
// Создаем StringReader на основе строки
StringReader sr = new StringReader(s);
// Последовательно читаем "кусочки" строки
string input;
while((input = sr.ReadLine()) != null)
Console.WriteLine(input);
sr.Close();