【问题标题】:C# Generics InheritanceC# 泛型继承
【发布时间】:2011-05-01 22:01:28
【问题描述】:

我有以下课程

public class AccountingBase<TItemType> where TItemType : AccountingItemBase

在我的 AccountingItemBase 中,我有以下属性:

public virtual AccountingBase<AccountingItemBase> Parent { get; set; }

在我的 AccountingBase 中,我正在尝试执行以下操作

item.Parent = this;

从逻辑上讲,这应该可以工作,因为 TItemType 继承自 AccountingItemBase,但我收到以下错误:

> Error 1 Cannot implicitly convert type
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TItemType>'
> to
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TGS.MySQL.DataBaseObjects.AccountingItemBase>'

如何将子属性的父属性设置为自身(在父类内部)

【问题讨论】:

  • 愚蠢的问题,我可以看到TItemType 的声明(包括命名空间)吗?
  • @drachenstern:愚蠢的问题,哪个? OP还是你的? :->
  • @drachenstern: TItemType 是一个类型参数。它没有单独的声明。
  • @hermeister der welten ~ 我的。
  • 有人在 /facepalm 日标记我……我有一种感觉,我会一遍又一遍地做这件事……一遍又一遍……我的咖啡呢?

标签: c# generics inheritance polymorphism


【解决方案1】:

不,你的直觉是错误的。它不应该工作,因为泛型类在 .NET 中不是变体。

TItemType 继承自 AccountingItemBase 并不意味着 AccountingBase&lt;TItemType&gt; 继承自 AccountingBase&lt;AccountingItemBase&gt;。假设AccountingBase&lt;TItemType&gt; 有一个TItemType 类型的字段。那么如果你的直觉是正确的,你可以这样写:

AccountingBase<SomeSubtype> x = new AccountingBase<SomeSubtype>();
AccountingBase<AccountingItemBase> y = x;
y.SomeField = new OtherSubtype();

这显然会破坏类型安全,因为当被视为 AccountingBase&lt;SomeSubtype&gt; 时,该字段的类型应为 SomeSubtype,但您已将 OtherSubtype 类型的值放入其中!

基本上,通用方差是一个复杂的话题。

我建议您阅读 Eric Lippert 的长而详细的blog post series 以了解更多信息。或者我有一个来自NDC 2010 的视频,您可能会觉得它很有用。基本上在 .NET 4 中存在 一些 通用差异,但它是有限的。

现在,你可以在你的情况下做什么:

  • 您可以创建一个 nongeneric 基类,AccountingBase 继承自该基类。这可能是最好的主意。然后将Parent 属性的类型设为非泛型类型。
  • 您可以使 AccountingBase 在其自身及其父级中都具有通用性...但这最终会导致递归问题,实际上...

【讨论】:

  • @Alexander:不,但我喜欢将我的写作总体上视为一种教学。
  • @Jon Skeet ~ 先生,你做得很好。我不想看到你走。 PS:chat.stackoverflow.com/transcript/message/55711#55711
  • 感谢您的出色回答,我最初设计了我的 AccoutningBaseItem 泛型类型来克服这个问题(以便 AccountingBaseItem 知道它是什么子类),但这开始让我很恼火,我必须通过一个额外的无缘无故地打字,感觉设计得不对。我将按照您在第一点中的建议进行操作,使accountingbase 继承自非泛型类型。感谢您的链接,我会先阅读它们。
  • @Alexander,这算不算恭维? :)
  • @Benjol,其实我在我花了4年的大学里感觉非常缺乏这样的专业人士。相比之下,我认识了很多当地的专业人士,他们不教学生他们知道什么。我觉得有点残忍。我不知道,只是问问。
【解决方案2】:

除了 Jon 的选择之外,您还可以:

  • 创建一个接口IAccountingBase,仅提供AccountingItemBase 完成其工作所需的有限访问(类似于非泛型基类,但进一步抽象。)

  • 重组您的代码,使 AccountingItemBase 不需要 Parent 引用来完成其工作。我的经验是循环依赖(Owner 知道 Items 知道 Owner)是 Child 实例承担太多责任的设计的症状。有时您可以通过将功能移至 Parent 或将其移至在单个 Parent 的上下文中对多个 Item 执行复杂操作的更高级别的类来解决此问题,从而无需每个 Item 具有 Parent 引用。例如,如果您的项目公开了与帐户对帐相关的函数,您可能有一个 AccountReconciler 类,而不是将这些函数放在项目上。

【讨论】:

  • 我需要父引用,因为它用于存储在数据库中,以便NHibernate在保存/更新时知道它属于哪个AccountingItem。
猜你喜欢
  • 1970-01-01
  • 2011-08-20
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-17
  • 1970-01-01
相关资源
最近更新 更多