Программирование >>  Программирование с использованием ajax 

1 ... 114 115 116 [ 117 ] 118 119 120 ... 396


В случае предоставления параметра обобщенному типу, как было в List<Card> выше, он может называться закрытым (closed) обобщенным типом, так же как и наследовани£ от List<T> может аналогичным образом называться наследованием от открытого (open) обобщенного типа.

Обобщенные операции

Переопределенные операции реализуются в С# точно так же, как и другие методы, и, следовательно, могут реализоваться и в обобщенных классах. Например, в Farm<T> можно определить следующую операцию неявного преобразования:

public static implicit operator List<Animal>(Farm<T> farm) {

List<Animal> result = new List<Animal> ();

foreach (T animal in farm)

result.Add(animal);

return result;

Это позволит при необходимости получать доступ к объектам Animal в Farm<T> напрямую как к List<Animal>. Подобное может оказаться удобным для сложения двух экземпляров Farm<T> с помощью, например, показанных ниже операций:

public static Farm<T> operator +(Farm<T> farml, List<T> farm2) {

Farm<T> result = new Farm<T>(); foreach (T animal in farml) {

result.Animals.Add(animal);

foreach (T animal in farm2) {

if (!result.Animals.Contains(animal)) {

result.Animals.Add(animal);

return result;

public static Farm<T> operator +(List<T> farml, Farm<T> farm2) {

return farm2 + farml;

Это позволит складывать вместе экземпляры Farm<Animal> и Farm<Cow> следующим образом:

Farm<Animal> newFarm = farm + dairyFarm;

В этом коде dairyFarm (экземпляр Farm<Cow>) неявно преобразуется в экземпляр List<Animal>, который пригоден для использования в перегруженной операции + в

Farm<T>.

Может показаться, что подобного легко добиться и путем использования следующего кода:



public static Farm<T> operator +(Farm<T> farml, Farm<T> farm2)

Farm<T> result = new Farm<T>(); foreach (T animal in farml) {

result.Animals.Add(animal);

foreach (T animal in farm2)

if (!result.Animals.Contains(animal))

result.Animals.Add(animal);

return result;

Однако поскольку Farm<Cow> не может преобразовываться Farm<Animal>, операция суммирования будет заканчиваться ошибкой. Чтобы устранить эту проблему, можно воспользоваться следующей операцией преобразования:

public static implicit operator Farm<Animal>(Farm<T> farm) {

Farm<Animal> result = new Farm<Animal>();

foreach (T animal in farm)

result.Animals.Add(animal);

return result;

При наличии такой операции экземпляры Farm<T>, вроде Farm<Cow> смогут преобразовываться в экземпляры Farm<Animal>, что устранит проблему. Применять можно любой из продемонстрированных методов, но последний все-таки более предпочтителен по причине простоты.

Обобщенные структуры

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

public struct MyStruct<Tl, Т2> {

public TI iteml; public T2 item2;

Определение обобщенных интерфейсов

в этой главе уже встречалось несколько обобщенных интерфейсов: в частности, это были интерфейсы из пространства имен Systems . Collections . Generic вроде IEnumerable<T>, который использовался в последнем примере. Для определения обобщенных интерфейсов применяются те же самые приемы, что и для определения обобщенных классов:



interface MyFarminglnterfасе<Т> where Т : Animal {

bool AttemptToBreed(Т animall, T animal2);

T OldestlnHerd

get;

Здесь обобщенный параметр Т используется для указания типа в двух аргументах метода AttemptToBreed () и в свойстве OldestlnHerd.

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

Определение обобщенных методов

в последнем практическом занятии был использован метод GetCows (), в пояснениях к которому было сказано, что можно было бы создать и более универсальную версию данного метода, применив обобщенный метод. В этом разделе как раз и будет показано, как подобное возможно. Обобщенный метод - это такой метод, в котором возвращаемый тип и/или типы параметров определяются параметром или параметрами обобщенного типа:

public Т GetDefault<T>() {

return default (Т);

В этом типичном примере, чтобы вернуть значение по умолчанию для типа Т используется рассматривавшееся ранее в главе ключевое слово default. Вызывается этот метод следующим образом:

int myDefaultInt = GetDefault<T> ();

Отвечающий за тип параметр Т предоставляется во время вызова метода.

Этот тип Т идет отдельно от типов, используемых для предоставления классам параметров обобщенного типа. На самом деле обобщенные методы могут реализоваться и не обобщенными классами:

public class Defaulter {

public Т GetDefault<T>О {

return default(T);

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

public class Defaulter<T>

public Т GetDefault<T>О {

return default(T);



1 ... 114 115 116 [ 117 ] 118 119 120 ... 396

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика