Подготовка к сертификационному экзамену Microsoft 70-483 «Programming in C#»
Во время подготовки к экзамену номер 70–483 нашел множество разрозненных сайтов с различными ссылками на мануалы, которые мне немного помогли. Но, что помогло мне больше, так это то, что я составил для себя памятку на нескольких страницах, выдержками из которой и хочу поделиться.Целью не является подробное описание C#, целью является освежить в памяти и заострить внимание на некоторых необходимых темах. Если какие-то темы вам незнакомы, то это значит, что у вас есть пробелы, которые необходимо устранить.Раскрывать вопросы тестирования я не могу (да и не помню я уже их), но, если многие из перечисленных ниже нюансов, трюков и тонкостей, помогут вам, то вы на меня не обижайтесь (написано с иронией).Начнем с простых вещей, о которых часто забывают, но которые часто используют в тестах: Для того, чтобы объявить переменную типа int, и присвоить ей сразу значение 0, можно сделать так: var myInt=0; или так int myInt=0; Для того, чтобы объявить переменную типа int, и задать сразу ей значение по умолчанию, нужно сделать так: int myInt = new int (); Explicit and Implicit типизация
int i = 42; // это explicit типизация — указан тип переменной int var i = 42; //, а это уже implicit типизация. Компилятор задает переменной тип исходя из ее значения. Используйте implicit типизацию при: Анонимных типах — var anonymousType = new { Name = «Alex» }; Получении результата запроса LINQ — var queryExpression = from c in customers where c.Name == «Andrey» select c; Использовании complex generic типов — var searchList = new Dictionary (); Implicit типизация возможна только для локальных переменных.Boxing/UnboxingBoxing — это конвертация value типа в тип referenceUnboxing наоборот — конвертация reference типа в value. Для Unboxing-а необходим Cast.Boxing/Unboxing копирует значение переменной.Boxing с точки зрения скорости вычислений — операция занимающая довольно много процессорных ресурсов.Простой пример:
int i = 123; // Следующая строчка упаковывает переменную i (происходит boxing) object o = i; // object — это тип reference тип, а int — это тип value j = (int)o; // unboxing — распаковка Интересный пример ошибки: double e = 2.718281828459045; object o = e; // box // int ee = (int)o; // вызовет runtime exception, так как o не может быть распознано как тип int int ee = (int)(double)o; // сделает unboxing без ошибки Еще пример: int count=1; object countObject=count; // значение count скопировано в переменную countObject — это boxing count+=1; // count уже равен 2, а значение countObject все еще 1 count=(int)countObject; // теперь и count равно 1 — это был unboxing Оператор ? называется null-coalescing operator. Он возвращает левое значение, в случае, если оно не равно null, в ином случае правое значение. Пример: int? x = null; // здесь int? означает что это Nullable type т.е. что можно объекту присвоить null int y = x? -1; // В этом случае y равен -1 потому что x равен null Оператор ?: называется conditional operator. Он возвращает одно из двух значений исходя из булева выражения. Если выражение равно true, то возвращается первое значение, в ином случае — второе. Для примера 2 аналогичных кода: if (input<0) // используя конструкцию if-else classify = "negative"; else classify = "positive";
classify = (input < 0) ? "negative" : "positive"; // используя conditional operator ?: LINQЛюбой объект, который реализует интерфейс IEnumerable или IQueryable может быть запрошен используя LINQ.Можно использовать как orderby … descending так и OrderByDescendingorderby h.State, h.City – здесь orderby пишется слитно, однако group h by h.State раздельно ( есть вариант записи заглавными буквами GroupBy )Predicate – это условие, которое характеризует субъект. Например: where i % 2 == 0 Есть 2 варианта записи LINQ ( синтаксис метода/method и синтаксис запроса/query ): var data=Enumerable.Range(1,100); var method=data.Where(x=>x%2==0).Select (x=>x.ToString ()); var query=from d in data where d%2==0 select d.ToString (); Простые методы LINQ: var values=new[]{«A», «B», «C», «B», «B», «A», «B»}; var distinct=values.Distinct (); // только неуникальные значения var first=values.First (); var firstordef=values.FirstOrDefault (); var twoval=values.Skip (2).Take (2); Интересна возможность вместо && использовать where несколько раз. Например: var evenNumbers = from i in myArray where i % 2 == 0 where i > 5 select i; Можно использовать функции в качестве фильтра. Например: var evenNumbers = from i in myArray where IsEvenAndGT5(i) select i; static bool IsEvenAndGT5(int i) { return (i % 2 == 0 && i > 5); } Если необходимо выбрать несколько значений, то нужно использовать new { } var names = from p in people select new { p.FirstName, p.LastName }; Причем, можно задать даже псевдонимы: var names = from p in people select new { First = p.FirstName, Last = p.LastName };
var names = people.Select (p => new { p.FirstName, p.LastName }); // вариант запроса с синтаксисом метода LINQ deferred execution — до тех пор, пока элемент не вызывается запрос не выполняется. Пример: int[] myArray = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var evenNumbers = from i in myArray where i % 2 == 0 select i; foreach (int i in evenNumbers) { Console.WriteLine (i); // выводим результат LINQ запроса } myArray[1] = 12; // изменяется элемент массива из которого происходит выборка запросом foreach (int i in evenNumbers) // здесь еще раз происходит вызов запроса LINQ { Console.WriteLine (i); // выводится первым элементом уже 12, а не 2 } //, а вот следующий запрос это Immediate Execution. Данные извлекаются сразу var evenNumbersCount=(from i in myArray where i % 2 == 0 select i).Count (); Версия сборки состоит из четырех частей: Major, Minor, Build, and RevisionДля установки сборки в GAC (Global Assembly Cache) необходима утилита Global Assembly Cache tool (Gacutil.exe). В командной строке вводится команда: gacutil –iНо необходимо, чтобы сборка была подписана ключом строгого имени с помощью средства SNПример создания ключа: «C:\GACKey\GACkey.snk» sn –kСборка со строгим именем (strong name) состоит из 5-ти частей: Friendly Name, Version, Culture, Public Key Token, and Processor ArchitectureПодписывая Ваши сборки, храните ключ в надежном месте, а разработчикам выдайте открытую часть ключа, что позволит им использовать сборки без полной подписи.Выделить открытую часть ключа можно следующей командой: Sn.exe –p «ключ.snk» «открытый ключ.snk»
Так как версия сборки важна в тот момент, когда runtime пытается найти сборку, то вы можете публиковать различные версии одной и той же сборки в GAC и избежать проблем, которые случаются с обычными dll.Это называется side-by-side hosting, при котором множество версий одной и той же сборки хостятся одновременно на одном компьютере (начиная с .Net 4).
Shallow copy — ловушка при копировании массивовПри копировании объектов ссылочного типа может быть скопирован указатель на значение, а не само значение. Пример:
Person[] orginal = new Person[1]; orginal[0] = new Person () { Name = «John» }; Person[] clone = (Person[])orginal.Clone (); clone[0].Name = «Mary»; // что интересно — теперь и original[0] и clone[0] содержат «Mary» так как массив ссылочного типа
Person[] orginal = new Person[1];
orginal[0] = new Person () { Name = «John» };
Person[] clone = (Person[])orginal.Clone ();
clone[0] = new Person () { Name = «Bob» };
// что интересно теперь original[0]=«John», а clone[0]=«Bob»
// т.к. ссылка на первый элемент массива original была заменена новым созданным элементом
Closures (замыкания)
var funcs = new List
var funcs = new List
Что такое WinMD? WinMD — это по сути dll, но с возможностями cross platform. То есть можно создать WinMD и назначить платформы в которых она будет использоваться (например: WP8, WinRT, WPF…). По сути, добавление каждой платформы сужает возможности сборки
PDB это акроним для Program database filePDB содержит отладочные данные и сведения о состоянии проекта, позволяющие выполнять последовательную компоновку отладочной конфигурации программыЛюбой имеющий доступ к dll/exe файлу может легко произвести реверс инжиниринг для того, чтобы генерировать исходный код с PDB или без него, используя такие средства, как например, reflector. Так что, предоставление или не предоставление PDB никак не влияет не безопасность кода.
Implicit и Explicit реализации интерфейсаДопустим, что у нас есть 2 интерфейса с одинаковым методом:
interface InterfaceOne { void InterfaceMethod (); } interface InterfaceTwo { void InterfaceMethod (); } Мы создаем класс, наследуемый от двух интерфейсов и в нем объявляем метод interfaceMethod: public class MyClass: InterfaceOne, InterfaceTwo { public void InterfaceMethod () { Console.WriteLine («Угадай метод какого класса вызван?»); } } Сейчас мы использовали Implicit реализацию интерфейса.А если мы укажем наименование интерфейса, то это будет Explicit реализация: public class MyClass: InterfaceOne, InterfaceTwo { void InterfaceOne.InterfaceMethod () { Console.WriteLine («Сейчас легко угадать какого это класса метод, правда?»); } void InterfaceTwo.InterfaceMethod () { Console.WriteLine («Сейчас легко угадать какого это класса метод, правда?»); } } В информатике отражение или рефлексия (синоним интроспекция, англ. reflection) означает процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения.Пример: void Method () { var horse=new Animal (); var type=horse.GetType (); var method=type.GetMethod («Speak»); var value=(string)method.Invoke (horse, null); // value=«hello»; } public class Animal { public string Speak () { return «hello»; } } При рефлексии сборку можно загрузить различными способами: Assembly.LoadFrom () может сделать перенаправление на другую аналогичную сборкуAssembly.LoadFile () загружает конкретно сборку из файла.Assembly.Load () загружает сборку по указанию ее полного имениРазница между Convert и Parse методами в том, что Parse принимает только строку как вводное значение, в то время, как Convert может принимать и другие типы данных.Разница между Parse/TryParse и Convert в том, что Convert может принимать нулевые значения и не выбрасывает ArgumentNullException.
Для представления положительной и отрицательной бесконечности в C# имеется две специальные константы: System.Double.NegativeInfinity и System.Double.PositiveInfinityNegativeInfinity — Значением этой константы является результат деления отрицательного числа на нуль, также Данная константа возвращается в случае, если результат операции меньше, чем минимальное значение (MinValue).PositiveInfinity — результат деления положительного числа на 0. Константа возвращается в случае, если значение больше, чем MaxValue.Infinity включает в себя как NegativeInfinity так и PositiveInfinity
Ключевое слово unchecked используется для подавления проверки переполнения при выполнении арифметических операций и преобразований с данными целого типа. Если среда unchecked удалена, возникает ошибка компиляции. 2 примера:
unchecked { int1 = 2147483647 + 10; } int1 = unchecked (2147483647 + 10); По умолчанию C# не выбрасывает исключение, если при сужающем/narrowing преобразовании возникает ошибка с int и float типами.Для того, чтобы исключение возникало можно использовать ключевое слово checked. Пример: checked { int big = 1000000; short small = (short)big; } Также можно в свойствах проекта поставить галочку о возникновении исключения при overflow/underflowФорматирование
Console.WriteLine (somevariable.ToString («c»)) // форматирует в денежный формат // например указав somevariable.ToString («C3», new System.Globalization.CultureInfo («fr-FR»)) в случае если somevariable=123.4562 получим -123,456 € // ToString («d») или ToString («D») форматирует число в виде decimal // можно указать число в виде минимального количества символов. Например, указав («D6») получим из -1234 число -001234 DateTime.Now.ToString («D») // в случае, если параметром является дата, форматирует в короткий формат даты = DateTime.Now.ToShortDateString () DateTime.Now.ToString («d») // длинный формат даты Rethrow exceptionСтек ошибки очищается каждый раз, когда выбрасывается ошибка.
static string ReadAFile (string fileName) { string result = string.Empty; try { result = File.ReadAllLines (fileName); } catch (Exception ex) { throw ex; // Это отобразит ReadAFile в StackTrace — не совсем верное решение throw; // Это же отобразит ReadAllLines в StackTrace — лучше использовать такое } Рекомендуется использовать просто throw, так как в таком случае сохранится информация об исходной ошибке.Как вариант можно создать свою ошибку — custom exception
[Serializable ()] public class YourCustomException: System.Exception { // конструктор принимает текст как параметр public YourCustomException (string msg) : base (msg) {
} } И после можно выбрасывать ошибку: try { throw new YourCustomException («Вам нельзя вводить текст в это поле»); // какой-то код } catch (YourCustomException e){} Не следует наследовать от System.ApplicationException. В идее было, что все C# runtime ошибки должны наследоваться от System.Exception, а все custom exceptions от System.ApplicationException. Но в реалии класс System.ApplicationException не используется совсем.В блока try/catch/finally — finally выполняется всегда. Только в случае вызова в коде Environment.FailFast (String) или FailFast (String, Exception), которые прерывают текущий процесс, в случае каких-либо критических повреждений в работе приложения, выполнение программы будет прервано и finally не будет выполнено.
CodeDOM — это набор классов, которые позволяют генерировать код.Класс System.CodeDom.CodeCompileUnit — это класс верхнего топ-уровня, контейнер для всех объектов в генерируемом классе.Класс System.CodeDom.CodeDOMProvider генерирует класс файла на C#, VB или JScript.
Структуры как и классы могут иметь методы, свойства, конструкторы и др.Структуры в отличие от классов не могут содержать деструкторы (фактически деструкторы это Finalize методы ~ИмяКласса которые позволяют уничтожить объект)Нельзя объявить пустой конструктор для структуры.Также структуры не могут иметь иерархии наследования (для экономии памяти). В C# структуры запечатаны — implicitly sealed. Что означает, что наследовать от структуры нельзя.Структуры — это value тип данных = хранится в стеке.Классы — это reference тип данных = хранится в куче (heap).В C# к Value типу данных относятся структуры и перечисления (structs и enumerations).Структуры в свою очередь делятся на подкатегории: числовой тип (целочисленный — integral types, с плавающей точкой — floating-point types, 128-и разрядный decimals), булев тип (bool) и пользовательские структуры.Перечисления это набор типов, объявленный с помощью ключевого слова enum.У value типа данных есть ограничения. Вы не можете наследовать от value типа, а также value тип не может содержать в себе значение null.
enum Months {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sept, Oct, Nov, Dec}; // можно использовать не int, а другой числовой тип для enum enum Months: byte {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sept, Oct, Nov, Dec};
string name = Enum.GetName (typeof (Months), 8); Console.WriteLine («Восьмой месяц в enum это » + name);
Console.WriteLine («Числовые значения Months enum:»); foreach (int values in Enum.GetValues (typeof (Months))) { Console.WriteLine (values); } Класс Interlocked — Предоставляет атомарные операции для переменных, общедоступных нескольким потокам (операции Decrement (Int), Increment (Int), Add (Int, Int)) Значение переменной будет изменено одновременно для всех потоков.Метод CompareExchange — сравнивает два значения на равенство и, если они равны, заменяет одно из значений. Interlocked.CompareExchange (ref value, newvalue, comparevalue) Метод Exchange — задает переменную указанным значением — как атомарная операция и возвращает исходное значение. Пример: if (Interlocked.Exchange (ref isInUse, 1) ==0){ // какой-то код } Параметры, передаваемые функциям static int CalculateBMI (int weight, int height) { return (weight * 703) / (height * height); } Стандартно функция вызывается так: CalculateBMI (123, 64); Если не помнить порядок, то можно вызывать функцию, указывая названия: CalculateBMI (weight: 123, height: 64); CalculateBMI (height: 64, weight: 123); Можно сперва указать параметр по порядку, а затем по имени CalculateBMI (123, height: 64); Но нельзя указывать сперва параметр по имени, а затем по порядку (вызовет ошибку) //CalculateBMI (weight: 123, 64); Можно указывать значения для параметров по умолчанию и вызывать после функцию без указания этих параметров: public void ExampleMethod (int required, string optionalstr = «default string», int optionalint = 10) Использование StringWriter и StringReader для записи и чтения строк StringWriter strwtr = new StringWriter (); for (int i=0; i < 10; i++) strwtr.WriteLine("This is i: " + i); StringReader strrdr = new StringReader(strwtr.ToString()); // Сейчас читаем из StringReader. string str = strrdr.ReadLine(); while(str != null) { str = strrdr.ReadLine(); Console.WriteLine(str); Сравнение Generics и ArrayList var objects=new ArrayList(); objects.Add(1); objects.Add(2); objects.Add("three”); // ArrayList принимает различные типы дынных
var list=new List