Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Преимущества универсальных шаблонов

Поиск

Универсальные шаблоны предоставляют решение для ограничения более ранних версий среды CLR и языка C#, в которых обобщения достигались за счет приведения типов к универсальному базовому типу Object и из него. Путем создания универсального класса можно создать коллекцию, которая была бы строго типизирована во время компиляции.

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

// The.NET Framework 1.1 way to create a list: System.Collections.ArrayList list1 = new System.Collections.ArrayList(); list1.Add(3); list1.Add(105);   System.Collections.ArrayList list2 = new System.Collections.ArrayList(); list2.Add("It is raining in Redmond."); list2.Add("It is snowing in the mountains.");  

Однако за удобство приходится платить. Любые ссылки или типы значения, добавляемые к классу коллекции ArrayList, неявно приводятся к Object. Если в качестве элементов выступают типы значений, то для них необходимо выполнить упаковку-преобразование при добавлении к списку и распаковку-преобразование при извлечении из списка. Операции приведения, упаковки-преобразования и распаковки-преобразования снижают производительность. Влияние операций упаковки-преобразования и распаковки-преобразования в сценариях обработки больших коллекций может быть весьма значительным.

 


The other limitation is lack of compile-time type checking; because an ArrayList casts everything to Object, there is no way at compile-time to prevent client code from doing something such as this:

System.Collections.ArrayList list = new System.Collections.ArrayList(); // Add an integer to the list. list.Add(3); // Add a string to the list. This will compile, but may cause an error later. list.Add("It is raining in Redmond."); int t = 0; // This causes an InvalidCastException to be returned. foreach (int x in list) { t += x; }

Although perfectly acceptable and sometimes intentional if you are creating a heterogeneous collection, combining strings and ints in a single ArrayList is more likely to be a programming error, and this error will not be detected until runtime.

In versions 1.0 and 1.1 of the C# language, you could avoid the dangers of generalized code in the.NET Framework base class library collection classes only by writing your own type specific collections. Of course, because such a class is not reusable for more than one data type, you lose the benefits of generalization, and you have to rewrite the class for each type that will be stored.

What ArrayList and other similar classes really need is a way for client code to specify, on a per-instance basis, the particular data type that they intend to use. That would eliminate the need for the upcast to T:System.Object and would also make it possible for the compiler to do type checking. In other words, ArrayList needs a type parameter. That is exactly what generics provide. In the generic List<<(Of <T>)>> collection, in the N:System.Collections.Generic namespace, the same operation of adding items to the collection resembles this:

// The.NET Framework 2.0 way to create a list List<int> list1 = new List<int>(); // No boxing, no casting: list1.Add(3); // Compile-time error: // list1.Add("It is raining in Redmond.");

For client code, the only added syntax with List<(Of <<T>)>> compared to ArrayList is the type argument in the declaration and instantiation. In return for this slightly more coding complexity, you can create a list that is not only safer than ArrayList, but also significantly faster, especially when the list items are value types.


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

ß-----

Несмотря на то, что комбинирование строк и ints в единый класс коллекции ArrayList вполне допустимо, а иногда и специально выполняется (при создании разнородной коллекции), во многих случаях это может привести к ошибке программы, которую можно будет обнаружить только при выполнении.

В версиях языка C# 1.0 и 1.1 можно избежать неприятностей, вызванных использованием обобщенного кода в классах коллекции библиотеки базового класса платформы.NET Framework только путем написания пользовательских коллекций особого типа. Конечно, пользователь теряет преимущества обобщения из-за того, что такие классы можно использовать только для одного типа данных, и необходимо переписывать класс для каждого типа сохраняемых данных.

Что действительно необходимо для класса коллекции ArrayList и других подобных классов — это возможность указать для каждого отдельного экземпляра в клиентском коде определенный тип данных, который они должны использовать. Это устранит необходимость приведения к типу T:System.Object и даст компилятору возможность проверить тип. Другими словами, классу коллекции ArrayList необходим параметр типа. Это как раз то, что имеется в универсальном шаблоне. В универсальном шаблоне коллекции List<(Of <(T>)>) в пространстве имен N:System.Collections.Generic та же операция добавления элементов в коллекцию выглядит следующим образом:

// The.NET Framework 2.0 way to create a list List<int> list1 = new List<int>();   // No boxing, no casting: list1.Add(3);   // Compile-time error: // list1.Add("It is raining in Redmond.");  

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


Generic Type Parameters

In a generic type or method definition, a type parameters is a placeholder for a specific type that a client specifies when they instantiate a variable of the generic type. A generic class, such as GenericList<T>, cannot be used as-is because it is not really a type; it is more like a blueprint for a type. To use GenericList<T>, client code must declare and instantiate a constructed type by specifying a type argument inside the angle brackets. The type argument for this particular class can be any type recognized by the compiler. Any number of constructed type instances can be created, each one using a different type argument, as follows:

GenericList<float> list1 = new GenericList<float>(); GenericList<ExampleClass> list2 = new GenericList<ExampleClass>(); GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();

In each of these instances of GenericList<T>, every occurrence of T in the class will be substituted at run time with the type argument. By means of this substitution, we have created three separate type-safe and efficient objects using a single class definition.



Поделиться:


Последнее изменение этой страницы: 2017-01-19; просмотров: 123; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.222.67.8 (0.006 с.)