继承中的循环泛型类型 - 为什么它有效



请考虑以下事项:

public class EntityBase<TEntity>
{
    public virtual void DoSomethingWhereINeedToKnowAboutTheEntityType()
    {
    }
}
public class PersonEntity : EntityBase<PersonEntity>
{
    public override void DoSomethingWhereINeedToKnowAboutTheEntityType()
    {
    }
}

我将其添加到代码中并运行它并且工作正常,但我很惊讶我可以继承一个定义基于继承类的类。

当我尝试它时,我期望它要么不编译,要么一旦实际调用就会失败。

您可以使用接口执行类似操作:

public interface IEntityBase<TEntity>
{}
public class PersonEntity : IEntityBase<PersonEntity>
{}

我实际上已经使用界面将我的代码从前者切换到后者,但我仍然很好奇为什么会这样。

它之所以有效,是因为没有理由不工作。 EntityBase<PersonEntity>不继承PersonEntity,它只是引用类型。基类知道自己的派生类没有技术问题。这也可以(即使这个特定的例子是一个坏主意):

public class A
{
    public B AsB()
    {
        return this as B;
    }
}

public class B : A
{
}

我很惊讶我可以继承一个定义基于继承类的类。

小心 - 你继承的是一个类,其定义涉及任意Type,就是全部。所有这些都是合法的:

class O : EntityBase<object>
class S : EntityBase<String>
class Q : EntityBase<Q>

你在EntityBase的定义中所说的只是TEntity应该是一种类型——嗯,PersonEntity是一种类型,不是吗?那么为什么它不应该有资格成为TEntity呢?没有理由不 - 所以它有效。

您可能会担心定义的顺序,但请记住,在编译单元中,所有内容都"立即"定义 - 在"其他任何东西(包括它自己!)可以引用它之前,PersonEntity都需要"编译"没有任何意义。事实上,你甚至被允许

class A : EntityBase<B>
class B : EntityBase<A>

如果需要这样的事情,任何可以想象的"编译顺序"都行不通。

一个非常简单的例子是通用接口IComparable<T>。通常,您可以像这样实现它:

class MyClass : IComparable<MyClass> {/*...*/}

通用模板的这种实现只是说MyClass对象可以与其他MyClass对象进行比较。如您所见,心智模型没有问题。我可以很好地理解一个类的概念,其对象可以在它们之间进行比较,而无需了解该类的任何其他内容。

这里的要点是模板参数仅由泛型类或接口使用,但它们根本不需要通过继承来关联。 IComparable<MyClass>不会继承自MyClass。所以没有循环。

最新更新