Общий "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; }
}
Ответы
Ответ 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();