Ограниченные интерфейсы и конструкторы

40

Применение ограничения на интерфейс

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

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

where T : имя_интерфейса

где T — это имя параметра типа, а имя_интерфейса — конкретное имя ограничиваемого интерфейса. В этой форме ограничения может быть указан список интерфейсов через запятую. Если ограничение накладывается одновременно на базовый класс и интерфейс, то первым в списке должен быть указан базовый класс.

Применение ограничения new() на конструктор

Ограничение new() на конструктор позволяет получать экземпляр объекта обобщенного типа. Как правило, создать экземпляр параметра обобщенного типа не удается. Но это положение изменяет ограничение new(), поскольку оно требует, чтобы аргумент типа предоставил конструктор без параметров. Им может быть конструктор, вызываемый по умолчанию и предоставляемый автоматически, если явно определяемый конструктор отсутствует или же конструктор без параметров явно объявлен пользователем. Накладывая ограничение new(), можно вызывать конструктор без параметров для создания объекта.

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

using System;

namespace ConsoleApplication1
{
    interface IUserInfo
    {
        string Name { get; set; }
        int Age { get; set; }
    }

    // Создадим класс, реализующий интерфейс IUserInfo
    class AllInfoUser : IUserInfo
    {
        public AllInfoUser() { }
        public AllInfoUser(string Family, string uName, int uAge)
        {
            this.Family = Family;
            this.Name = uName;
            this.Age = uAge;
        }

        public string Name { get; set; }
        public int Age { get; set; }
        public string Family { get; set; }

        public override string ToString()
        {
            string s = String.Format("Информация о пользователе: \n{0} {1} {2}\n",this.Name,Family,this.Age);
            return s;
        }
    }

    // Обобщенный класс использующий ограничение на интерфейс и конструктор
    class Info<T> where T : IUserInfo, new()
    {
        T[] UserList;
        int i;

        // Следующий код доступен благодаря ограничению на конструктор
        T obj = new T();

        public Info()
        {
            UserList = new T[3];
            i = 0;
        }

        public void Add(T obj)
        {
            if (i == 3) return;
            UserList[i] = obj;
            i++;
            return;
        }

        public void ReWrite()
        {
            foreach (T t in UserList)
                Console.WriteLine(t.ToString());
        }
    }

    class Program
    {
        static void Main()
        {
            Info<AllInfoUser> database1 = new Info<AllInfoUser>();
            database1.Add(new AllInfoUser(uName: "Alex", Family: "Erohin", uAge: 26));
            database1.Add(new AllInfoUser(uName: "Alexey", Family: "Volkov", uAge: 28));
            database1.Add(new AllInfoUser(uName: "Dmitryi", Family: "Medvedev", uAge: 50));

            database1.ReWrite();

            Console.ReadLine();
        }
    }
}

Что касается применения ограничения new(), то следует обратить внимание на три важных момента:

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