C# 泛型方法返回父方法中的子类型

C# 泛型方法返回父方法中的子类型,c#,generics,extension-methods,C#,Generics,Extension Methods,我在C语言中试验了几个星期的扩展方法,我发现了一些有趣的东西。我曾尝试为我的DTO构建泛型,如下所示: public class ParentDto{ public string attrStr{get;set;} } public static class ParentDtoExtensions{ public static T AttrStr<T>(this T parentDto, string attrStr) where T:ParentDto{

我在C语言中试验了几个星期的扩展方法,我发现了一些有趣的东西。我曾尝试为我的DTO构建泛型,如下所示:

public class ParentDto{
    public string attrStr{get;set;}
}

public static class ParentDtoExtensions{
    public static T AttrStr<T>(this T parentDto, string attrStr)
    where T:ParentDto{
        parentDto.attrStr = attrStr;
        return parentDto;
    }
}
return ((new ChildDto()).AttrStr("someString").ChildAttrStr("someOtherString"));
这对我很有吸引力。能够让monad ish setter以及其他方法返回调用类型对于链接代码块非常方便

然而,我希望能够将setter方法集成到我认为它们真正属于的父类中,同时维护上面显示的现有代码流,但我不知道有什么方法可以实现返回实现类的子类的方法。比如:

public class ParentDto{
    public string attrStr{get;set;}

    public T AttrStr<T>(string attrStr)
    where T:ParentDto{
        parentDto.attrStr = attrStr;
        return parentDto;
    }
}
但是这不起作用,因为编译器不知道调用类型。有人知道怎么做吗


请记住,我并不是在寻找关于我现有实现的代码气味的建议,因为我确信有更多的C-ish方法来实现这一点。

您可以执行以下操作,但在我看来,您的扩展方法要好得多:

public class ParentDto<T> where T : ParentDto<T> {
    public string attrStr{get;set;}

    public T AttrStr(string attrStr) {
        this.attrStr = attrStr;
        return (T)this;
    }
}
public sealed class ChildDto : ParentDto<ChildDto> {
    public string childAttrStr{get;set;}
    public ChildDto ChildAttrStr(string childAttrStr) {
        this.childAttrStr = childAttrStr;
        return this;
    }
}
有关此模式的更多信息以及在可能的情况下避免使用它的原因,请参阅


也就是说,我同意这是一种代码气味;您可能应该只使用属性设置器,而不是流畅的语法。但是,既然您没有在那里征求意见,我就到此为止。

如果您所做的只是在新对象上设置属性,那么您可以使用对象初始值设定项来执行此操作:

return new ChildDto()
    {
        attrStr = "someString",
        childAttrString = "someOtherString"
    }

在这种情况下,使用提供了一种你无法获得的灵活性。是的,我不太喜欢childto:ParentDto。在我看来,父类不应该为了可继承而走极端。顺便问一下,为什么LINQ可以使用可链接的方法,但这个例子不受欢迎?@zwerdlds不完全确定,这正是惯例。一个可能的原因是,当LINQ链接方法时,您不是在修改原始集合,而是在创建枚举集合的新方法。此外,围绕属性的某些约定可能不适用于方法,例如,它们不应该花费很长时间,它们不应该取决于您设置它们的顺序。当您删除这些约定时,需要更多的文档和阅读来理解setter是如何工作的。
return new ChildDto()
    {
        attrStr = "someString",
        childAttrString = "someOtherString"
    }