Обобщения

Поддержка обобщений (generics) — одно из самых замечательных средств С# и .NET. позволяют создавать открытые (open-ended) типы, которые преобразуются в закрытые во время выполнения. Каждый уникальный закрытый тип сам по себе уникален. Создавать экземпляры можно только для закрытых типов. При объявлении обобщенного типа указывается список параметров типа, для которых будут переданы аргументы-типы, позволяющие создать конкретный закрытый тип.

Ниже показан пример:

1
2
3
4
5
public class MyCollection<t>
{
public MyCollection () { }
private T[] storage;
}

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

В некоторой точке потребитель MyCollection объявляет то, что называется закрытым типом, подставляя конкретный тип, который должен представлять Т. Например, предположим, что какая-то другая сборка желает создать контейнерный тип MyCollection, содержащий члены типа int. Это можно сделать так, как показано в следующем коде:

1
2
3
4
public void SomeMethod ()
{
MyCollection<int> collectionOfNumbers = new MyCollection<int>();
}

MyCollection является примером закрытого типа. MyCollection может использоваться подобно любому другому объявленному типу, и он также следует всем тем же правилам, которым подчиняются другие необобщенные типы. Единственное отличие в том, что он порожден от обобщенного типа. В точке создания экземпляра IL-код реализации MyCollection подвергается JIT-компиляции таким образом, что все включения типа Т в реализации MyCollection заменяются типом int.

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

Например, MyCollection — совершенно отличный от MyCollection тип, и поступать так, как показано ниже, не допускается:

1
2
3
4
5
// ЭТО РАБОТАТЬ НЕ БУДЕТ! ! !
public void SomeMethod( MyCollection<int> intNumbers )  {
MyCollection<long> longNumbers = intNumbers;
// ОШИБКА!
}

Если вы знакомы с правилами ковариантности массивов, которые дают возможность выполнить следующую операцию, то наверняка обрадуетесь, узнав, что в С# 4.0 был добавлен синтаксис, позволяющий делать то же самое с обобщенными типами:

1
2
3
4
5
6
public void ProcessStrings ( string[] myStrings )  {
object [] objs = myStrings;
foreach ( object о in objs )  {
Console.WriteLine ( о );
}
}

Разница в том, что в случае ковариантности массивов источник и цель операции присваивания относятся к одному и тому же типу — System.Array. Правила ковариантности массивов просто позволяют присваивать один массив другому — до тех пор, пока объявленный тип элементов массива является неявно преобразуемым во время компиляции. Однако в случае двух сконструированных обобщенных типов мы имеем дело с совершенно разными типами.

Начиная с версии С# 4.0, в языке поддерживается ковариантность и контраваривантность между обобщенными интерфейсами и делегатами с типами-аргументами на основе ссылок.

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

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100