Универсальные классы и методы

Универсальные шаблоны представляют концепцию параметров типа для .NET, что позволяет проектировать классы и методы, которые откладывают спецификацию одного или нескольких типов до тех пор, пока класс или метод не будет объявлен и создан с помощью клиентского кода. Как пример, ниже показан класс с параметром T универсального типа. Этот класс может использоваться в другом клиентском коде, не требуя ресурсов и не создавая рисков, связанных с операциями приведения и упаковки-преобразования в среде выполнения.

// Declare the generic class.
public class GenericList<T>
{
    public void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        // Declare a list of type int.
        GenericList<int> list1 = new GenericList<int>();
        list1.Add(1);

        // Declare a list of type string.
        GenericList<string> list2 = new GenericList<string>();
        list2.Add("");

        // Declare a list of type ExampleClass.
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
        list3.Add(new ExampleClass());
    }
}

Универсальные классы и методы сочетают такие характеристики, как возможность многократного использования, типобезопасность и эффективность, которые не обеспечивают их неуниверсальные аналоги. Универсальные типы наиболее часто используются с коллекциями и методами, которые выполняют с ними операции. Пространство имен System.Collections.Generic содержит несколько универсальных классов коллекций. Неуниверсальные коллекции, например ArrayList, не рекомендуются и поддерживаются только для обеспечения совместимости. Дополнительные сведения см. в статье об универсальных шаблонах в .NET.

Вы также можете создавать настраиваемые универсальные типы и методы для предоставления собственных обобщенных решений и шаблонов разработки, которые являются типобезопасными и эффективными. В следующем примере кода показан простой универсальный класс связанного списка для демонстрационных целей. (В большинстве случаев следует использовать класс List<T>, предоставляемый .NET, вместо создания собственного.) Параметр типа T используется в нескольких расположениях, где обычно используется конкретный тип для указания типа элемента, хранящегося в списке. Он используется в следующих случаях:

  • в качестве типа параметра метода в методе AddHead;
  • в качестве типа возвращаемого значения свойства Data во вложенном классе Node;
  • в качестве типа закрытого члена data во вложенном классе.

T доступен для вложенного Node класса. Когда экземпляр GenericList<T> создается с конкретным типом, например GenericList<int>, каждое вхождение T будет заменено int.

// type parameter T in angle brackets
public class GenericList<T>
{
    // The nested class is also generic on T.
    private class Node
    {
        // T used in non-generic constructor.
        public Node(T t)
        {
            next = null;
            data = t;
        }

        private Node? next;
        public Node? Next
        {
            get { return next; }
            set { next = value; }
        }

        // T as private member data type.
        private T data;

        // T as return type of property.
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
    }

    private Node? head;

    // constructor
    public GenericList()
    {
        head = null;
    }

    // T as method parameter type:
    public void AddHead(T t)
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }

    public IEnumerator<T> GetEnumerator()
    {
        Node? current = head;

        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }
}

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

class TestGenericList
{
    static void Main()
    {
        // int is the type argument
        GenericList<int> list = new GenericList<int>();

        for (int x = 0; x < 10; x++)
        {
            list.AddHead(x);
        }

        foreach (int i in list)
        {
            System.Console.Write(i + " ");
        }
        System.Console.WriteLine("\nDone");
    }
}

Общие сведения об универсальных шаблонах

  • Используйте универсальные типы, чтобы получить максимально широкие возможности многократного использования кода, обеспечения безопасности типов и повышения производительности.
  • Чаще всего универсальные шаблоны используются для создания классов коллекций.
  • Библиотека классов .NET содержит несколько универсальных классов коллекций в пространстве имен System.Collections.Generic. Универсальные коллекции следует использовать везде, где это возможно, вместо таких классов, как ArrayList в System.Collections пространстве имен.
  • Вы можете создавать собственные универсальные интерфейсы, классы, методы, события и делегаты.
  • Универсальные классы можно ограничить, чтобы они разрешали доступ к методам только для определенных типов данных.
  • Сведения о типах, используемых в универсальном типе данных, можно получить во время выполнения с помощью отражения.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#.

См. также