C# 通用';t这';对于流利的课程

C# 通用';t这';对于流利的课程,c#,generics,fluent,fluent-interface,C#,Generics,Fluent,Fluent Interface,我正在构建一个fluent接口,其中有一个基类,包含fluent逻辑的大部分,还有一个派生类,添加了一些专门的行为。我面临的问题是从派生类型的实例调用时基类中fluent方法的返回类型。在调用基类的方法之后,只有基类的方法可用于进一步的流畅调用 改变调用方法的顺序将有助于编译,但会降低可读性,这在某种程度上是fluent接口的要点。是否有一种方法可以为基类定义某种类型的“This”类型,以便所有方法都返回相同的类型 例子 公共类字段 { 公共字段名(字符串名) { _名称=名称; 归还这个; }

我正在构建一个fluent接口,其中有一个基类,包含fluent逻辑的大部分,还有一个派生类,添加了一些专门的行为。我面临的问题是从派生类型的实例调用时基类中fluent方法的返回类型。在调用基类的方法之后,只有基类的方法可用于进一步的流畅调用

改变调用方法的顺序将有助于编译,但会降低可读性,这在某种程度上是fluent接口的要点。是否有一种方法可以为基类定义某种类型的“This”类型,以便所有方法都返回相同的类型

例子
公共类字段
{
公共字段名(字符串名)
{
_名称=名称;
归还这个;
}
}
公共专用字段:字段
{
public SpecialField Special(){返回此;}
}
// !!! 啊。Special不是Field类的成员。
var specialField=new specialField()
.姓名(“必应”)
.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; }
}
公共类字段:t此
这是什么地方
{
public t此名称(字符串名称){…}
}
公共专用字段:字段
{
public t此特殊(){返回此;}
}

在浏览了其他一些fluent API之后,我找到了如何实现它的方法。虽然没有那么干净,但效果很好。基本上,为要使用的每个派生类型引入一个中间基类,并将“ttthis”类型传递给实际实现

样品
公共类现场数据库
这是什么地方:野战基地
{
私有字符串\u名称;
公共t此名称(字符串名称)
{
_名称=名称;
把这个退回来;
}
}
公共类字段:FieldBase{}
公共类特殊字段数据库:FieldBase
此处:特殊字段数据库
{
public ttthis Special(){return(ttthis)this;}
}
公共类SpecialField:SpecialFieldBase{}
//是的,很管用!
var specialField=new specialField()
.姓名(“必应”)
.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; }
}
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();