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

Общий "TThis" для плавных занятий

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

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

Пример

public class Field<T>
{
    public Field<T> Name( string name )
    {
        _name = name;
        return this;
    }
}

public SpecialField<T> : Field<T>
{
    public SpecialField<T> Special(){ return this; }
}


// !!! Arrgh. Special is not a member of the Field<T> class.
var specialField = new SpecialField()
    .Name( "bing" )
    .Special();

Разбитое решение

Я попытался решить это, выполнив что-то вроде следующего, но это неправда С#:( но, по крайней мере, выражает, как я хотел бы закодировать интерфейс.

public class Field<T,TThis> : TThis
    where TThis : Field<T,TThis>
{
    public TThis Name( string name ){...}
}

public SpecialField<T> : Field<T,SpecialField<T>>
{
    public TThis Special(){ return this; }
}
4b9b3361

Ответ 1

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

Пример

public class FieldBase<T,TThis> 
    where TThis : FieldBase<T,TThis>
{
    private string _name;
    public TThis Name( string name ) 
    {
        _name = name;
        return (TThis)this;
    }
}

public class Field<T> : FieldBase<T,Field<T>>{}

public class SpecialFieldBase<T,TThis> : FieldBase<T,TThis>
    where TThis : SpecialFieldBase<T,TThis>
{
    public TThis Special(){ return (TThis)this; }
}

public class SpecialField<T> : SpecialFieldBase<T,SpecialField<T>>{}


// Yeah it works!
var specialField = new SpecialField<string>()
    .Name( "bing" )
    .Special();