Base Class Method return 派生的类型 class 可以吗?

Can a Base Class Method return the type of the derived class?

根据我读过的其他 posts,这似乎是不可能的,但我想我会 post 我想做什么,看看是否有人知道一个解法。

我正在尝试向从 Telerik Open Access 域模型生成的 classes 添加一个 "Clone()" 方法。没问题。我能够弄清楚如何将基础 class 添加到生成的实体模型,以便我可以通过它们的基础 class 识别那些 classes。 (All entities inherit from a base class)

我希望所有这些实体模型 classes 能够克隆自己。我也找到了解决方案。 (Deep Cloning Objects)

现在我有一个基础 class,我想向每个从该基础 class 派生的 class 添加一个 Clone() 函数。所以……看来base class 是自然放的地方……对吧?

public abstract class DBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }
}

我添加了 受保护的通用 Clone() 方法,因为在基础 class 级别我们不知道我们正在克隆的类型。 Clone() 方法需要由实体模型本身实现,以提供被克隆的特定类型。

public partial class DeliverableEntity
{
    public new DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

这工作正常,但不保证派生的classes将public只暴露一个Clone() 方法,所以我在基础上添加了一个 abstract Clone() 方法,它将 require派生的 class 来实现 public Clone() 方法。

public abstract class DarkRoomDBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }

    /// <summary>
    ///     Gets a deep COPY of the entity instance
    /// </summary>
    /// <returns></returns>
    public abstract DBEntityBase Clone();
}

我给它一个 return 类型的基 class 本身;每个实现都必须 return 一个遵循 DBEntityBase 的值,当然,所有派生的 classes 都这样做。由于 Clone() 方法是 return 派生的 class 本身的一种类型,那么......这似乎是可行的。

DeliverableEntity originalEntity = new DeliverableEntity();
DeliverableEntity clonedEntity   = originalEntity.Clone();

然而,在构建时,我收到错误..

'DeliverableEntity' does not implement inherited abstract member 'DBEntityBase.Clone()'

大概是由于 return 类型。

我知道我可以将 Clone() 方法放在一个单独的实用程序中 class 而不是直接在每个实体模型中实现它......这样可以解决我的问题(并且可能节省很多实现代码),但我仍然想知道为什么这行不通。看来应该有办法做到这一点。

更新

为了回应@Luann 的第一个回复(谢谢),我更改为 "override" ...

public partial class DeliverableEntity
{
    public override DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

现在收到以下错误...

return type must be 'DBEntityBase' to match overridden member 'DBEntityBase.Clone()'

解决方案

多亏了Flynn1179,我才得以再次前进。我想我会花点时间记录一下我在这里所做的以供将来参考..

我没有为 ORM 中的每个实体模型创建部分 class 来实现抽象方法,而是按照建议创建了一个扩展方法。

namespace DAL
{
    public partial class DeliverableEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemAttrEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }
}

namespace DAL
{
    public static class EntityExtensionMethods
    {
        public static T Clone<T>(this T entity) where T: DBEntityBase
        {
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(entity));
        }
    }
}

一些注意事项...

现在最酷的部分是所有实体都可以访问函数...

    // Create the original instances of the entities    
    DeliverableEntity origDeliverable       = new DeliverableEntity();
    DeliverableItemEntity origItem          = new DeliverableItemEntity();
    DeliverableItemAttrEntity origItemAttr  = new DeliverableItemAttrEntity();

    // now here's the magic 

    DeliverableEntity cloneDeliverable      = origDeliverable.Clone();
    DeliverableItemEntity cloneItem         = origItem.Clone();
    DeliverableItemAttrEntity cloneItemAttr = origItemAttr.Clone();

我喜欢这个解决方案,因为它具有基础 class 的简单性,其中实现是在单个位置定义的(而我正在考虑在每个派生 class 中单独实现抽象方法) 再加上因为它与 DBEntityBase class 相关联并且在同一个命名空间中,它成为由基 class 定义的“合同”的一部分,这意味着我可以指望它在我有 class 时可用=92=] 从 DEBentityBase 派生。

应大家的要求..

尝试扩展方法:

public T Clone<T>(this T obj) where T : DBEntityBase
{
  return /* insert code that creates clone here */
}

老实说,我认为这行不通,因为我预计 C# 无法准确确定它是什么的扩展。然而,显然,它确实如此!

新的 C# 版本 9.0 将支持 covariant returns,这意味着您可以覆盖 Clone() 和 return 更具体的类型。这将编译:

public partial class DeliverableEntity
{
    public override DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}