Подтвердить что ты не робот

С# generics: какая точка ограничения типа "X <T>, где T: X <T>"?

Чтение книги: NHibernate 3: Руководство для начинающих Я нашел фрагмент, который заставлял меня любопытно:

Время действия - Создание базового объекта

(...)

  • Добавить новый класс в папку Домен проекта и вызвать его Entity. Сделайте класс абстрактным и обобщенным в T. Ваш код должен выглядеть так же, как в следующем фрагменте кода:
 using System;

 namespace OrderingSystem.Domain
 {
     public abstract class Entity<T> where T : Entity<T>
     { }
 }

Мой вопрос: какова точка фрагмента where T : Entity<T>?

Я понимаю, что раздел where можно применить для добавления ограничений в тип T, но приведенный выше код выглядит так, что никогда не будет возможно создать экземпляр такого класса (если бы он не был абстрактным в любом случае).

4b9b3361

Ответ 1

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

abstract class Cloneable<T> where T : Cloneable<T>
{
    public abstract T Clone();
}

sealed class MyCloneable : Cloneable<MyCloneable>
{
    public override MyCloneable Clone()
    {
        return new MyCloneable();
    }
}

MyCloneable instance = new MyCloneable();
MyCloneable clone = instance.Clone();

ИЗМЕНИТЬ

Согласно комментарию @siride, это известно как любопытно повторяющийся шаблон шаблона. Эрик Липперт написал замечательную статью о ее применении в С#:

https://blogs.msdn.microsoft.com/ericlippert/2011/02/03/curiouser-and-curiouser/

P.S. И просто для того, чтобы проиллюстрировать, как выглядел бы приведенный выше пример, если бы вы убрали общее ограничение:

abstract class Cloneable
{
    public abstract Cloneable Clone();
}

sealed class MyCloneable : Cloneable
{
    public override Cloneable Clone()
    {
        return new MyCloneable();
    }
}

MyCloneable instance = new MyCloneable();
MyCloneable clone = (MyCloneable)instance.Clone(); // Note the cast.