Классы с родовыми параметрами. Универсализм.

Под универсальностью (genericity) понимается способность класса объявлять используемые им типы как параметры. Класс с параметрами, задающими типы, называется универсальным классом (generic class). Пример:

class SomeClass<T> // наш обобщенный класс

{

T first;

T second;

public SomeClass(T input1, T input2)

{

first = input1;

second = input2;

}

}

Ограничение универсальности

Пример:

class Work<T> where T: BaseClass // где Т является наследником от BaseClass

{

public T SomeField;

public Work(T input)

{

SomeField = input;

}

public void ShowData()

{

Console.WriteLine(SomeField.name); //теперь ошибки не будет.

Console.ReadKey();

}

}

С помощью выражения where T : BaseClass мы указываем, что используемый тип T обязательно должен быть классом BaseClass или его наследником.

В определении универсального типа предложение where позволяет задать ограничения для типов, которые можно использовать как аргументы для параметра типа, определенных в универсальном объявлении. Например, можно объявить универсальный класс MyGenericClass, чтобы параметр типа T реализовывал интерфейс IComparable<T>.

Наряду с ограничениями интерфейса предложение where может включать ограничение базового класса, согласно которому тип должен иметь указанный класс как базовый (либо быть таким классом) — только в этом случае его можно будет использовать как аргумент типа для соответствующего универсального типа. Если такое ограничение используется, оно должно быть указано перед любыми другими ограничениями данного параметра типа.

class MyClass<T, U>

where T : class

where U : struct

{ }

Предложение where также может включать ограничение конструктора. С помощью оператора new можно создать экземпляр параметра типа, однако для этого параметр типа должен ограничиваться ограничением конструктора new(). Ограничение new() сообщает компилятору о том, что все предоставленные аргументы типа должны иметь доступный конструктор без параметров (или конструктор по умолчанию). Пример:

public class MyGenericClass<T> where T : IComparable, new()

{

// The following line is not possible without new() constraint:

T item = new T();

}

Ограничение new() отображается в предложении where последним.

Атрибуты

Язык С# позволяет создавать атрибуты для различных элементов языка, таких как типы, методы, поля и свойства классов. Данные, хранимые в атрибутах, можно запрашивать во время выполнения приложения.Использование атрибутов позволяет получать метаданные периода выполнения.Каждый атрибут - это экземпляр класса, производного от System.Attribute.

Класс Attribute пространства имен System предоставляет следующие члены класса:

· GetType - получает объект типа Type текущего экземпляра;

· ToString - возвращает строку, описывающую данный объект;

· IsDefined - определяет, существует ли атрибуты заданного типа, назначенные указываемому члену класса;

· GetCustomAttribute - запрашивает атрибут заданного типа для указанного члена класса.

Для того, чтобы назначить атрибут элементу кода, можно:

1. Определить новый класс атрибута

2. Использовать существующий класс атрибута из библиотеки NET Framework.

Атрибут указывается в квадратных скобках перед элементом, которому он назначается. Назначаемый атрибут инициализируется вызовом конструктора с соответствующими параметрами.

Пример: класс System.ObsoleteAttribute позволяет помечать код и задавать информацию, которая будет отображаться как Warning во время компиляции приложения. Этот класс предназначается для возможности указания некоторого кода модуля как "устаревшего".

// Компилятор будет выдавать предупреждение при
// каждом вызове данного метода, которому назначен
// соответствующий атрибут.

[ObsoleteAttribute ("Сообщение, отображаемое компилятором как Warning")]
public static void M1( ) {return ; }

Также можно создавать собственные атрибуты. Для этого необходимо:

1. Создать новый класс и унаследовать класс System.Attribute

2. Создать поля и конструктор для сохранения различных объектов времени компиляции

Пример:

[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : System.Attribute

{
private string name; // Используются как
private int kod; // параметры атрибута


public MyAttribute(string name)
{ /
this.name = name;
this.kod = 12345; }

// Свойство Name
public string Name
{ get { return name; } }


// Свойство Kod
public int Kod
{

get { return kod; }
set {kod=value; }
}
}
}
// Для назначения некоторому классу данного
// атрибута перед объявлением класса следует
// указать строку типа [My("NameClass", Kod=123)]

Теги

XML комментарии, обозначаемые тройным слэшем (///), являются формой XML, используемой для документирования. Теги, используемые в комментариях, полностью настраиваемые; однако есть ряд тегов, которые согласованы с ECMA. Рекомендуемые теги имеют определенные значения для C# компилятора и Visual Studio IDE, но разработчики могут расширять этот рекомендуемый набор, чтобы проводить в жизнь корпоративные стандарты ведения документации, обеспечивать команды разработчиков совместимыми вариантами форматирования или добавлять любую дополнительную, по их мнению, необходимую информацию. Единственным ограничением в XML комментариях является то, что XML, размещенный в тегах, должен быть правильно построен. Это требование выдвигается C# компилятором, как частью процесса компиляции.

C# разработчики могут использовать XML комментарии, чтобы документировать код определенных пользователем типов, включая классы, делегаты, перечисления и структуры. Кроме того, XML комментарии могут быть применены к членам, включая поля, события, свойства, индексаторы и методы. Таким образом создаются стандартизированные комментарии, что облегчает работу разработчика. Кроме того при использовании стандартных тэгов IntelliSense будет автоматически отображать информацию о документированных методах и параметрах, также как и для методов, встроенных во фреймворк.

Список часто используемых тегов:

Тег Используется для
<c> одна строка исходного кода
<code> много строк исходного кода
<example> пример использования, можно использовать совместно с тегом <code>
<exception> позволяет указать, какие исключения наш метод может выдавать
<include> позволяет поставить ссылку на файл, в котором содержаться комментарии, используя XPath
<list> обычный список
<para> а это обычный параграф
<param> описания параметра метода, каждый параметр описывается отдельно
<paramref> позволяет указать, что слово внутри тега является параметром
<permission> позволяет описать права доступа к методу
<remarks> дополнительная информация, помимо тега <summary>
<returns> описание того, что метод возвращает
<see> позволяет указывать ссылки
<seealso> текст в секции «Смотри также»
<summary> общее описание
<value> позволяет описывать свойства

Корректность класса

Формула корректности программы (участка кода):

{P} A {Q}

Любое выполнение А, начинающееся в состоянии, где P истинно, завершится и в заключительном состоянии будет истинно Q. Формула корректности, называемая также триадой Хоара, - математическое понятие, а не программистская конструкция. Она не является частью языка программирования и введена для того, чтобы выражать свойства программных элементов. В этой формуле А, как было сказано, обозначает операцию, P и Q - свойства вовлекаемых в рассмотрение сущностей, называемые утверждениями (точный смысл этого термина будет определен ниже). Утверждение P называется предусловием, а Q - постусловием.

Класс, подобно всем остальным программным элементам, не может быть корректным или некорректным сам по себе, - только по отношению к некоторой спецификации. Инварианты, предусловия и постусловия, это способ задания спецификации класса. На этой основе можно приступать к определению корректности: класс корректен, если и только если его реализация, заданная подпрограммами, согласована с предусловиями, постусловиями и инвариантами. Предусловие называется условие, которое должно выполняться перед запуском подпрограммы, чтобы обеспечить её корректность (n > 0 для программы вычисления n!). Постусловие - этого условие, которое должно выполняться после работы программы (например a+b=0 для программы a=-b). Инвариантом называется условие, накладывающееся на все экземпляры класса. Например для класса массив верно, что текущий индекс больше нуля и меньше длины массива, в противном случае корректность не гарантируется.

Нотация {P} A {Q} поможет выразить наше определение более строго. Пусть C обозначает класс, Inv - инвариант, r - программа класса. Для каждой программы Bodyr - ее тело, prer(xr), postr(xr) - ее предусловие и постусловие с возможными аргументами xr. Если предусловие или постусловие для программы r опущены, то будем считать их заданными константой True. Наконец, пусть DefaultC обозначает утверждение, выражающее тот факт, что атрибуты класса C имеют значения по умолчанию, определенные их типами.

Тогда истинность класса задается утверждениями:

1. Любая процедура создания (конструктор в случае C#) при ее вызове с выполняемым предусловием должна вырабатывать начальное состояние, удовлетворяющее постусловию и инварианту:

{DefaultC and prep(xp)} Bodyp {postp(xp) and Inv}

2. Любая экспортируемая процедура r (публичный метод), вызываемая в корректном состоянии, удовлетворяющем предусловию и инварианту, должна завершаться в состояниях, удовлетворяющих постусловию и инварианту:

{prer(xr) and Inv} Bodyr {postr(xr) and Inv}

Стиль программирования

Станда́рт оформле́ния ко́да (станда́рт коди́рования, стиль программи́рования) (англ. coding standards, coding convention или programming style) — набор правил и соглашений, используемых при написании исходного кода на некотором языке программирования. Наличие общего стиля программирования облегчает понимание и поддержание исходного кода, написанного более чем одним программистом, а также упрощает взаимодействие нескольких человек при разработке программного обеспечения.

Сюда могут входить требования по именованию членов классов, пространств имён, функциональные имена переменных, размер кода одного метода и т.д.

В качестве примера можно привести некоторые рекомендации к написанию кода на C#

1. Имена классов, интерфейсов, пространств имён и всех публичных членов классов в стиле Pascal casing

2. Имена интерфейсов с префиксом I

3. Локальные переменные, аргументы методов и поля класса в стиле Camel casing

4. Функциональные имена переменных

5. Отсутствие методов с более чем 5 аргументами (в таком случае используются дополнительные типы данных)

6. Небольшие размеры методов

Задачи

Наши рекомендации