Полное руководство. С# 4.0
Полное руководство. С# 4.0 читать книгу онлайн
В этом полном руководстве по C# 4.0 — языку программирования, разработанному специально для среды .NET, — детально рассмотрены все основные средства языка: типы данных, операторы, управляющие операторы, классы, интерфейсы, методы, делегаты, индексаторы, события, указатели, обобщения, коллекции, основные библиотеки классов, средства многопоточного программирования и директивы препроцессора. Подробно описаны новые возможности C#, в том числе PLINQ, библиотека TPL, динамический тип данных, а также именованные и необязательные аргументы. Это справочное пособие снабжено массой полезных советов авторитетного автора и сотнями примеров программ с комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки.Книга рассчитана на широкий круг читателей, интересующихся программированием на C#.
В данной книге вы найдете:- Полное описание средств языка C#- Подробное рассмотрение новых средств в версии C# 4.0, в том числе PLINQ, библиотеку TPL, именованные и необязательные аргументы, динамический тип данных и многое другое- Сотни простых и понятных примеров программ с комментариями.- Самый полный источник информации по C#Благодаря поддержке параллельного языка интегрированных запросов (PLINQ) и библиотеки распараллеливания задач (TPL) версия 4.0 стала новой вехой в программировании на C#, и поэтому Герберт Шилдт, автор лучших книг по программированию, обновил и расширил свое классическое руководство, чтобы охватить в нем эти и другие нововведения. В книге подробно описываются языковые средства C#, даются профессиональные рекомендации и приводятся сотни примеров программ, охватывающих все аспекты программирования на C#, включая синтаксис, ключевые слова и основные библиотеки, не говоря уже о таких новшествах, как PLINQ, TPL, динамический тип данных, а также именованные и необязательные аргументы.Это необходимое каждому программирующему на C# справочное руководство написано простым и доступным языком, благодаря которому Герберт Шилдт стал таким популярным. В книге найдут ответы на насущные вопросы по C# как начинающие, так и опытные программисты.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Этой последовательностью кода можно пользоваться всякий раз, когда требуетсядинамически загружать и опрашивать сборку.
Но сборка совсем не обязательно должна быть исполняемым файлом с расширением .ехе. Сборки могут быть также в файлах динамически компонуемых библиотек(DLL) с расширением .dll. Так, если скомпилировать исходный файл MyClasses.csв следующей командной строке:csc /t:library MyClasses.es
то в итоге получится файл MyClasses.dll. Преимущество размещения кода в библиотеке DLL заключается, в частности, в том, что в этом случае метод Main() в исходномкоде не нужен, тогда как всем исполняемым файлам требуется определенная точкавхода, с которой должно начинаться выполнение программы. Именно поэтому классDemo содержит метод Main() в качестве такой точки входа. А для библиотеки DLL метод Main() не требуется. Если же класс MyClass нужно превратить в библиотеку DLL,то в вызов метода LoadFrom() придется внести следующее изменение.Assembly asm = Assembly.LoadFrom("MyClasses.dll");Полностью автоматизированное обнаружение типов
Прежде чем завершить рассмотрение рефлексии, обратимся к еще одному поучительному примеру. Несмотря на то что в программе из предыдущего примера классMyClass был полноценно использован без явного указания на его имя в программе,этот пример все же опирается на предварительную осведомленность о содержимомкласса MyClass. Так, в программе были заранее известны имена методов Set и Sum изэтого класса. Но с помощью рефлексии можно воспользоваться типом данных, ничего не зная о нем заранее. С этой целью придется извлечь все сведения, необходимыедля конструирования объекта и формирования вызовов соответствующих методов. Такой подход может оказаться пригодным, например, при создании инструментального средства визуального проектирования, поскольку он позволяет использовать типыданных, имеющиеся в системе.
Рассмотрим следующий пример, демонстрирующий полностью автоматизированное обнаружение типов. В этом примере сначала загружается сборка MyClasses.ехе,затем конструируется объект класса MyClass и далее вызываются все методы, объявленные в классе MyClass, причем о них ничего заранее неизвестно.// Использовать класс MyClass, ничего не зная о нем заранее.using System;using System.Reflection;class ReflectAssemblyDemo { static void Main() { int val; Assembly asm = Assembly.LoadFrom("MyClasses.exe"); Type[] alltypes = asm.GetTypes(); Type t = alltypes[0]; // использовать первый обнаруженный класс Console.WriteLine("Использовано: " + t.Name); ConstructorInfo[] ci = t.GetConstructors(); // Использовать первый обнаруженный конструктор. ParameterInfо[] cpi = ci[0].GetParameters(); object reflectOb; if(cpi.Length > 0) { object[] consargs = new object[cpi.Length]; // Инициализировать аргументы. fox(int n=0; n < cpi.Length; n++) consargs[n] = 10 + n * 20; // Сконструировать объект. reflectOb = ci[0].Invoke(consargs); } else reflectOb = ci[0].Invoke(null); Console.WriteLine("nВызов методов для объекта reflectOb."); Console.WriteLine(); // Игнорировать наследуемые методы. MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); // Вызвать каждый метод. foreach(Methodlnfo m in mi) { Console.WriteLine("Вызов метода {0} ", m.Name); // Получить параметры. ParameterInfo[] pi = m.GetParameters(); // Выполнить методы. switch(pi.Length) { case 0: // аргументы отсутствуют if(m.ReturnType == typeof(int)) { val = (int) m.Invoke(reflectOb, null); Console.WriteLine("Результат: " + val); } else if(m.ReturnType == typeof(void)) { m.Invoke(reflectOb, null); } break; case 1: // один аргумент if(pi[0].ParameterType == typeof(int)) { object[] args = new object[1]; args[0] = 14; if((bool) m.Invoke(reflectOb, args)) Console.WriteLine("Значение 14 находится между x и у"); else Console.WriteLine("Значение 14 не находится между х и у"); } break; case 2: // два аргумента if((pi[0].ParameterType == typeof(int)) && (pi[1].ParameterType == typeof (int))) { object[] args = new object[2]; args[0] = 9; args[1] = 18; m.Invoke(reflectOb, args); } else if((pi[0].ParameterType == typeof(double)) && (pi[1].ParameterType == typeof(double))) { object[] args = new object[2]; args[0] = 1.12; args[1] = 23.4; m.Invoke(reflectOb, args); } break; } Console.WriteLine(); } }}
Эта программа дает следующий результат.Использовано: MyClassКонструирование класса MyClass(int).Значение х: 10, значение у: 10Вызов методов для объекта reflectOb.Вызов метода SumРезультат: 20Вызов метода IsBetweenЗначение 14 не находится между х и уВызов метода SetВ методе Set(int, int). Значение х: 9, значение у: 18Вызов метода SetВ методе Set(double, double). Значение х: 1, значение у: 23Вызов метода ShowЗначение х: 1, значение у: 23
Эта программа работает довольно просто, но все же требует некоторых пояснений.Во-первых, получаются и используются только те методы, которые явно объявленыв классе MyClass. Для этой цели служит форма BindingFlags метода GetMethods(),чтобы воспрепятствовать вызову методов, наследуемых от объекта. И во-вторых, количество параметров и возвращаемый тип каждого метода получаются динамически,а затем определяются и проверяются в операторе switch. На основании этой информации формируется вызов каждого метода.Атрибуты
В C# разрешается вводить в программу информацию декларативного характерав форме атрибута, с помощью которого определяются дополнительные сведения(метаданные), связанные с классом, структурой, методом и т.д. Например, в программе можно указать атрибут, определяющий тип кнопки, которую должен отображатьконкретный класс. Атрибуты указываются в квадратных скобках перед тем элементом,к которому они применяются. Следовательно, атрибут не является членом класса, нообозначает дополнительную информацию, присоединяемую к элементу.Основы применения атрибутов
Атрибут поддерживается классом, наследующим от класса System.Attribute.Поэтому классы атрибутов должны быть подклассами класса Attribute. В классеAttribute определены основные функциональные возможности, но далеко не все онинужны для работы с атрибутами. В именах классов атрибутов принято употреблятьсуффикс Attribute. Например, ErrorAttribute — это имя класса атрибута, описывающего ошибку.
При объявлении класса атрибута перед его именем указывается атрибутAttributeUsage. Этот встроенный атрибут обозначает типы элементов, к которымможет применяться объявляемый атрибут. Так, применение атрибута может ограничиваться одними методами.Создание атрибута
В классе атрибута определяются члены, поддерживающие атрибут. Классы атрибутов зачастую оказываются довольно простыми и содержат небольшое количествополей или свойств. Например, атрибут может определять примечание, описывающееэлемент, к которому присоединяется атрибут. Такой атрибут может принимать следующий вид. [AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute { string pri_remark; // базовое поле свойства Remark public RemarkAttribute(string comment) { pri_remark = comment; } public string Remark { get { return pri_remark; } }}
Проанализируем этот класс атрибута построчно.
Объявляемый атрибут получает имя RemarkAttribute. Его объявлению предшествует встроенный атрибут AttributeUsage, указывающий на то, что атрибутRemarkAttribute может применяться ко всем типам элементов. С помощью встроенного атрибута AttributeUsage можно сузить перечень элементов, к которым можетприсоединяться объявляемый атрибут. Подробнее о его возможностях речь пойдетдалее в этой главе.
Далее объявляется класс RemarkAttribute, наследующий от класса Attribute.В классе RemarkAttribute определяется единственное закрытое поле pri_remark,поддерживающее одно открытое и доступное для чтения свойство Remark. Это свойство содержит описание, связываемое с атрибутом. (Конечно, Remark можно былобы объявить как автоматически реализуемое свойство с закрытым аксессором set, норади наглядности данного примера выбрано свойство, доступное только для чтения.)В данном классе определен также один открытый конструктор, принимающий строковый аргумент и присваивающий его свойству Remark. Этим пока что ограничиваются функциональные возможности класса RemarkAttribute, готового к применению.Присоединение атрибута