Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 134 135 136 137 138 139 140 141 142 ... 407
специальных обобщенных типов. Давайте посмотрим, как включать обобщения в свои проекты. Первым делом будет построен обобщенный метод обмена. Начните с создания нового проекта консольного приложения по имени CustomGenericMethods.

Построение специальных обобщенных методов представляет собой более развитую версию традиционной перегрузки методов. В главе 2 вы узнали, что перегрузка — это действие по определению нескольких версий одного метода, которые отличаются друг от друга количеством или типами параметров.

Хотя перегрузка является полезным средством объектно-ориентированного языка, проблема заключается в том, что при этом довольно легко получить в итоге огромное количество методов, которые по существу делают одно и то же. Например, пусть необходимо создать методы, которые позволяют менять местами два фрагмента данных посредством простой процедуры. Вы можете начать с написания нового статического класса с методом, который способен оперировать целочисленными значениями:

using System;

namespace CustomGenericMethods

{

  static class SwapFunctions

  {

    // Поменять местами два целочисленных значения.

    static void Swap(ref int a, ref int b)

    {

      int temp = a;

      a = b;

      b = temp;

    }

  }

}

Пока все идет хорошо. Но теперь предположим, что нужно менять местами также и два объекта Person; действие потребует написания новой версии метода Swap():

// Поменять местами два объекта Person.

static void Swap(ref Person a, ref Person b)

{

  Person temp = a;

  a = b;

  b = temp;

}

Вне всяких сомнений вам должно быть ясно, чем все закончится. Если также понадобится менять местами два значения с плавающей точкой, два объекта растровых изображений, два объекта автомобилей, два объекта кнопок или что-нибудь еще, то придется писать дополнительные методы, что в итоге превратится в настоящий кошмар при сопровождении. Можно было бы построить один (необобщенный) метод, оперирующий с параметрами типа object, но тогда возвратятся все проблемы, которые были описаны ранее в главе, т.е. упаковка, распаковка, отсутствие безопасности в отношении типов, явное приведение и т.д.

Наличие группы перегруженных методов, отличающихся только входными аргументами — явный признак того, что обобщения могут облегчить ситуацию. Рассмотрим следующий обобщенный метод Swap<T>(), который способен менять местами два значения типа Т:

// Этот метод будет менять местами два элемента

// типа, указанного в параметре <Т>.

static void Swap<T>(ref T a, ref T b)

{

  Console.WriteLine("You sent the Swap() method a {0}", typeof(T));

  T temp = a;

  a = b;

  b = temp;

}

Обратите внимание, что обобщенный метод определен за счет указания параметра типа после имени метода, но перед списком параметров. Здесь заявлено, что метод Swap<T>() способен оперировать на любых двух параметрах типа <Т>. Для придания некоторой пикантности имя замещаемого типа выводится на консоль с использованием операции typeof() языка С#. Взгляните на показанный ниже вызывающий код, который меняет местами целочисленные и строковые значения:

Console.WriteLine("***** Fun with Custom Generic Methods *****n");

// Поменять местами два целочисленных значения.

int a = 10, b = 90;

Console.WriteLine("Before swap: {0}, {1}", a, b);

SwapFunctions.Swap<int>(ref a, ref b);

Console.WriteLine("After swap: {0}, {1}", a, b);

Console.WriteLine();

// Поменять местами два строковых значения.

string s1 = "Hello", s2 = "There";

Console.WriteLine("Before swap: {0} {1}!", s1, s2);

SwapFunctions.Swap<string>(ref s1, ref s2);

Console.WriteLine("After swap: {0} {1}!", s1, s2);

Console.ReadLine();

Вот вывод:

***** Fun with Custom Generic Methods *****

Before swap: 10, 90

You sent the Swap() method a System.Int32

After swap: 90, 10

Before swap: Hello There!

You sent the Swap() method a System.String

After swap: There Hello!

Главное преимущество такого подхода в том, что придется сопровождать только одну версию Swap<T>(), однако она в состоянии работать с любыми двумя элементами заданного типа в безопасной в отношении типов манере. Еще лучше то, что находящиеся в стеке элементы остаются в стеке, а расположенные в куче — соответственно в куче.

Выведение параметров типа

При вызове обобщенных методов вроде Swap<T>() параметр типа можно опускать, если (и только если) обобщенный метод принимает аргументы, поскольку компилятор в состоянии вывести параметр типа на основе параметров членов. Например, добавив к операторам верхнего уровня следующий код, можно менять местами два значения System.Boolean:

// Компилятор выведет тип System.Boolean.

bool b1 = true, b2 = false;

Console.WriteLine("Before swap: {0}, {1}", b1, b2);

SwapFunctions.Swap(ref b1, ref b2);

Console.WriteLine("After swap: {0}, {1}", b1, b2);

Несмотря на то что компилятор может определить параметр типа на основе типа данных, который применялся в объявлениях b1 и b2, вы должны выработать привычку всегда указывать параметр типа явно:

SwapFunctions.Swap<bool>(ref b1, ref b2);

Такой подход позволяет другим программистам понять, что метод на самом деле является обобщенным. Кроме того, выведение типов параметров работает только в случае, если обобщенный метод принимает, по крайней мере, один параметр. Например, пусть в классе Program определен обобщенный метод DisplayBaseClass<T>():

static void DisplayBaseClass<T>()

{

  // BaseType - метод, используемый в рефлексии;

  // он будет описан в главе 17

  Console.WriteLine("Base class of {0} is: {1}.",

                     typeof(T), typeof(T).BaseType);

}

В таком случае при его вызове потребуется указать параметр типа:

...

// Если метод не принимает параметров,

// то должен быть указан параметр типа.

DisplayBaseClass<int>();

DisplayBaseClass<string>();

// Ошибка на этапе компиляции! Нет параметров?

// Должен быть предоставлен заполнитель!

// DisplayBaseClass();

Console.ReadLine();

Разумеется, обобщенные методы не обязаны быть статическими, как в приведенных выше примерах. Кроме того, применимы все правила и варианты для необобщенных методов.

Создание специальных обобщенных структур и классов

Так как вы уже знаете, каким образом определять и вызывать обобщенные методы, наступило время уделить внимание конструированию обобщенной структуры (процесс построения обобщенного класса идентичен) в новом проекте консольного приложения по имени GenericPoint. Предположим, что вы построили обобщенную

1 ... 134 135 136 137 138 139 140 141 142 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий