问题 适用于流利课程的通用'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();

破解

我尝试通过执行类似下面的操作来解决它,但它无效C#:(但至少表达了我想如何编码接口。

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; }
}

5264
2017-11-05 02:19


起源



答案:


在探索其他一些流畅的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();

12
2017-11-05 03:32



这看起来与协方差和反方差有关。 blogs.msdn.com/b/csharpfaq/archive/2010/02/16/... 在“对象理论”一书中,他们花了一两个时间来讨论“自我”代表键入的难度,这就是为什么要弄清楚“自我”或“这个”的类型是关于共同和反对方差的问题的主要动机。 lucacardelli.name/TheoryOfObjects.html - Dennis
你的代码不起作用。 - adeel41


答案:


在探索其他一些流畅的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();

12
2017-11-05 03:32



这看起来与协方差和反方差有关。 blogs.msdn.com/b/csharpfaq/archive/2010/02/16/... 在“对象理论”一书中,他们花了一两个时间来讨论“自我”代表键入的难度,这就是为什么要弄清楚“自我”或“这个”的类型是关于共同和反对方差的问题的主要动机。 lucacardelli.name/TheoryOfObjects.html - Dennis
你的代码不起作用。 - adeel41