繁体   English   中英

基类方法可以返回派生类的类型吗?

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

根据我读过的其他帖子,这似乎是不可能的,但我想我会发布我想要做的事情,看看是否有人知道解决方案。

我正在尝试向从 Telerik 开放访问域模型生成的类添加“Clone()”方法。 没问题。 我能够弄清楚如何将基类添加到生成的实体模型中,以便我可以通过它们的基类来识别这些类。 所有实体都继承自基类

我希望所有这些实体模型类都能够自我克隆。 我也为此找到了解决方案。 深度克隆对象

现在我有一个基类,我想向从该基类派生的每个类添加一个 Clone() 函数。 所以......似乎基类是放置它的自然场所......对吗?

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()方法,因为在基类级别我们不知道要克隆的类型。 Clone() 方法需要由实体模型本身实现,以提供被克隆的特定类型。

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

这工作正常,但不能保证派生类会公开公开 Clone() 方法,因此我向基类添加了一个抽象 Clone()方法,这将要求派生类实现公共 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();
}

我给它一个基类本身的返回类型; 每个实现都必须返回一个符合 DBEntityBase 的值,当然,所有派生类都这样做。 由于 Clone() 方法正在返回派生类本身的类型,因此......这似乎是有道理的。

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

但是,在构建时,我收到错误..

'DeliverableEntity' 没有实现继承的抽象成员 'DBEntityBase.Clone()'

大概是由于返回类型。

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

更新

为了回应@Luann 的第一个回复(谢谢),我将更改为“覆盖”......

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

现在收到以下错误...

返回类型必须是“DBEntityBase”以匹配覆盖的成员“DBEntityBase.Clone()”

解决方案

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

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

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));
        }
    }
}

一些注意事项...

  • 将此类放在与实体模型相同的命名空间中。 如果它在不同的命名空间中,那么您将需要添加该命名空间才能访问该方法。
  • 我将泛型类型的约束定义为 only 和所有继承DBEntityBase类的类。 由于我让所有实体模型类都从这个基类派生,我知道它们都会公开这个方法,但任何不是从这个类派生的类都不会有这个能力。
  • 扩展方法和包含它的类必须是静态的

现在很酷的部分是所有实体都可以访问该功能......

    // 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();

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

应大众要求..

尝试扩展方法:

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

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

新的 C# 版本 9.0 将支持协变返回,这意味着您可以覆盖Clone()并返回更具体的类型。 这将编译:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM