簡體   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