在C#中这种明显的自引用的目的是什么?


21

我正在评估一个名为Piranha(http://piranhacms.org/)的开源CMS ,以便在我的一个项目中使用。至少对于我来说,我发现以下代码有趣且有点混乱。可以帮助我理解为什么类从相同类型的基类继承吗?

public abstract class BasePage<T> : Page<T> where T : BasePage<T>
{
    /// <summary>
    /// Gets/sets the page heading.
    /// </summary>
    [Region(SortOrder = 0)]
    public Regions.PageHeading Heading { get; set; }
}

如果BasePage<T>要定义的类,为什么要继承Page<T> where T: BasePage<T>?它有什么具体目的?



7
尽管投票和票数不高,但我认为社区对此有误。这是一个明确陈述的问题,与特定且不平凡的设计决策有关,这是该网站的本质。
罗伯特·哈维

只需徘徊并在关闭时重新打开即可。
David Arno

阅读有关F界多态性的概念的文章:)
Eyvind

1
@Eyvind我确实做到了。对于那些有兴趣阅读F-界多态性,这里是链接staff.ustc.edu.cn/~xyfeng/teaching/FOPL/lectureNotes/...
Xami日元

Answers:


13

可以帮助我理解为什么类从相同类型的基类继承吗?

它不是,它是从继承的Page<T>,但是T它本身受制于必须由派生自的类型进行参数化BasePage<T>

为了推断原因,您必须查看type参数T的实际使用方式。经过一些挖掘之后,当您沿继承链向上移动时,您将来到该类:

github

public class GenericPage<T> : PageBase where T : GenericPage<T>
{
    public bool IsStartPage {
        get { return !ParentId.HasValue && SortOrder == 0; }
    }

    public GenericPage() : base() { }

    public static T Create(IApi api, string typeId = null)
    {
        return api.Pages.Create<T>(typeId);
    }
}

据我所知,泛型约束的唯一目的是确保该Create方法返回尽可能少的抽象类型。

虽然不确定是否值得,但是也许背后有一些充分的理由,或者仅仅是为了方便,或者背后没有太多实质,而且这是避免演员表转换的一种过于复杂的方法(BTW,我并不意味着这里就是这种情况,我只是说人们有时会这样做。

请注意,这并不能让他们避免反射-的api.Pages是网页,其获得资源库typeof(T).Name,并将其作为typeIdcontentService.Create方法(见这里)。


5

此类型的一个常见用法与自类型的概念有关:自定义类型可解析为当前类型。假设您要使用clone()方法定义接口。该clone()方法必须始终返回调用它的类的实例。您如何声明该方法?在具有自我类型的泛型系统中,这很容易。您只是说它返回了self。因此,如果我有一个类Foo,则必须声明clone方法以返回Foo。在Java和(通过粗略搜索)C#中,这不是一个选择。相反,您会看到类似在该类中看到的声明。重要的是要了解这与自类型不同,它提供的限制也较弱。如果您有一个Foo和一个Bar类都源自BasePage,您可以(如果我没记错的话)将Foo定义为Bar。这可能很有用,但我认为通常在大多数情况下,它会像自类型一样使用,并且可以理解,即使您可以随意使用并替换为其他类型,也不应该这样做。我很早以前就尝试过这个想法,但得出的结论是,由于Java泛型的局限性,这样做不值得。C#泛型当然具有更全面的功能,但似乎也有相同的限制。

另一种使用这种方法的时间是在构建类似图形的类型(例如树或其他递归结构)时。该声明允许类型满足Page的要求,但可以进一步优化类型。您可能会在树状结构中看到它。例如,Node可以通过参数化a,Node以允许实现定义它们不仅仅是包含任何类型的Node的树,而是包含Node的特定子类型(通常是它们自己的类型)的树。


3

作为实际编写代码的人,我可以确认Filip是正确的,并且自引用泛型实际上是在基类上提供类型化Create方法的便利。

就像他提到的那样,仍然有很多反思,最后只使用类型名称来解析页面类型。这样做的原因是,您也可以加载动态模型,即在无需访问最初创建它的CLR类型的情况下实现模型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.