Как правильно писать тесты 46 Цикл разработки 46 Структура проекта с тестами 51 Утверждения (Asserts) 52 Утверждения в форме ограничений 54 Категории 56
Вид материала | Тесты |
СодержаниеОтсутствие поддержки ограничений при использовании операций Создание обобщенных базовых классов Создание обобщенных интерфейсов |
- Некорректные задания, 1276.79kb.
- К техническому регламенту, 835.7kb.
- Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке разработки, 494.44kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 652.85kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 623.18kb.
- Правительства Российской Федерации от 11. 11. 2005 N 679 о порядке разработки и утверждения, 533.6kb.
- Постановления Правительства Российской Федерации от 11. 11. 2005 n 679 о порядке разработки, 613.63kb.
- Об утверждении требований к схемам теплоснабжения, порядку их разработки и утверждения, 450.79kb.
- Рабочая программа учебной дисциплины. Общие требования, порядок разработки, согласования, 414.77kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 1924.26kb.
Отсутствие поддержки ограничений при использовании операций
При создании обобщенных методов для вас может оказаться сюрпризом появление ошибок компилятора, когда с параметрами типа используются операции C# (+, -, *, == и т.д.). Например, я уверен, вы сочли бы полезными классы Add(), Subtract(), Multiply() и Divide(), способные работать с обобщенными типами.
// Ошибка компиляции!
// Нельзя применять операции к параметрам типа!
public class BasicMath
{
public T Add(T arg1, T arg2)
{ return arg1 + arg2; }
public T Subtract(T arg1, T arg2)
{ return arg1 - arg2; }
public T Multiply(T arg1, T arg2)
{ return arg1 * arg2; }
public T Divide(T arg1, T arg2)
{ return arg1 / arg2; }
}
Как ни печально, этот класс BasicMath
// Только для иллюстрации!
// Этот программный код не является допустимым в C# 2.0.
public class BasicMath
operator *, operator /
{
public T Add(T arg1, T arg2)
{ return arg1 + arg2; }
public T Subtract(T arg1, T arg2)
{ return arg1 - arg2; }
public T Multiply(T arg1, T arg2)
{ return arg1 * arg2; }
public T Divide(T arg1, T arg2)
{ return arg1 / arg2; }
}
Создание обобщенных базовых классов
Перед рассмотрением обобщенных интерфейсов следует указать на то, что обобщенные классы могут быть базовыми для других классов и могут таким образом определять любое число виртуальных и абстрактных методов. Однако производные типы должны подчиняться определенным правилам, вытекающим из природы обобщенной абстракции. Во-первых, если обобщенный класс расширяется необобщенным, то производный класс должен конкретизировать параметр типа.
// Предположим, что создан пользовательский
// обобщенный класс списка.
public class MyList
{
private List
}
// Конкретные типы должны указать параметр типа,
// если они получаются из обобщенного
// базового класса.
public class MyStringList : MyList
{}
Кроме того, если обобщенный базовый класс определяет обобщенные виртуальные или абстрактные методы, производный тип должен переопределить эти обобщенные методы, используя конкретизированный параметр типа.
// Обобщенный класс с виртуальным методом.
public class MyList
{
private List
public virtual void PrintList(T data) { }
}
public class MyStringList : MyList
{
// В производных методах нужно заменить параметр типа,
// используемый в родительском классе.
public override void PrintList(string data) { }
}
Если производный тип тоже является обобщенным, дочерний класс может (опционально) использовать заменитель типа в своем определении. Однако знайте, что любые ограничения, размещенные в базовом классе, должны “учитываться” и производным типом. Например:
// Обратите внимание, теперь здесь имеется ограничение,
// требующее конструктор по умолчанию.
public class MyList
{
private List
public virtual void PrintList(T data) { }
}
// Производный тип должен учитывать ограничения базового.
public class MyReadOnlyList
{
public override void PrintList(T data) { }
}
Создание обобщенных интерфейсов
Вы уже видели при рассмотрении пространства имен System.Collections.Generic, что обобщенные интерфейсы в C# также допустимы (например, IEnumerable
public interface IBinaryOperations
{
T Add(T arg1, T arg2);
T Subtract(T arg1, T arg2);
T Multiply(T arg1, T arg2);
T Divide(T arg1, T arg2);
}
Известно, что интерфейсы остаются почти бесполезными, пока они не реализованы некоторым классом или структурой. При реализации обобщенного интерфейса поддерживающий его тип указывает тип заполнителя.
public class BasicMath : IBinaryOperations
{
public int Add(int arg1, int arg2)
{ return arg1 + arg2; }
public int Subtract(int arg1, int arg2)
{ return arg1 - arg2; }
public int Multiply(int arg1, int arg2)
{ return arg1 * arg2; }
public int Divide(int arg1, int arg2)
{ return arg1 / arg2; }
}
После этого вы можете использовать BasicMath, как и ожидали.
static void Main(string[] args)
{
Console.WriteLine("***** Обобщенные интерфейсы *****\n");
BasicMath m = new BasicMath();
Console.WriteLine("1 + 1 = {0}", m.Add(1, 1));
Console.ReadLine();
}
Если вместо этого требуется создать класс BasicMath, действующий на числа с плавающим десятичным разделителем, можно конкретизировать параметр типа так.
public class BasicMath : IBinaryOperations
{
public double Add(double arg1, double arg2)
{ return arg1 + arg2; }
...
}