Ограничения ссылочного типа и типа значения

41

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

where T : class

В этой форме с оператором where ключевое слово class указывает на то, что аргумент T должен быть ссылочного типа. Следовательно, всякая попытка использовать тип значения, например int или bool, вместо T приведет к ошибке во время компиляции. Ниже приведена общая форма ограничения типа значения:

where T : struct

В этой форме ключевое слово struct указывает на то, что аргумент T должен быть типа значения. (Напомним, что структуры относятся к типам значений.) Следовательно, всякая попытка использовать ссылочный тип, например string, вместо T приведет к ошибке во время компиляции. Но если имеются дополнительные ограничения, то в любом случае class или struct должно быть первым по порядку накладываемым ограничением.

Как правило, пустое значение нельзя присвоить переменной типа значения. (Исключением из этого правила является обнуляемый тип, который представляет собой специальный тип структуры, инкапсулирующий тип значения и допускающий пустое значение (null).) Следовательно, в отсутствие ограничения такое присваивание было бы недопустимым, и код не подлежал бы компиляции. Это один из тех случаев, когда для обобщенного кода может оказаться очень важным различие между типами значений и ссылочными типами.

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

Давайте рассмотрим пример:

using System;

namespace ConsoleApplication1
{
    struct UI
    {
        public UI(string Name, int Age)
        {
            this.Name = Name;
            this.Age = Age;
        }

        public string Name;
        public int Age;
    }

    // Обобщенный класс, использующий ограничение на тип значения
    class UserInfo<T> where T : struct
    {
        T obj;

        public UserInfo(T ob)
        {
            obj = ob;
        }
    }

    class Program
    {
        static void Main()
        {
            UI user1 = new UI(Name: "Alexandr", Age: 26);
            UserInfo<UI> user = new UserInfo<UI>(user1);
        }
    }
}

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

Пройди тесты
Лучший чат для C# программистов