基本クラスメソッドは派生クラスのタイプを返すことができますか?

ゲイリーO.ステンストロム

私が読んだ他の投稿から、これは不可能かもしれないようですが、私がやろうとしていることを投稿して、誰かが解決策を知っているかどうかを確認したいと思いました。

Telerik Open Accessドメインモデルから生成されたクラスに「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.Clone()」と一致するには、戻り値の型は「DBEntityBase」である必要があります

解決

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

注意すべきいくつかの事柄...

  • このクラスをエンティティモデルと同じ名前空間に配置します。別の名前空間にある場合は、メソッドにアクセスするためにその名前空間を追加する必要があります。
  • ジェネリック型の制約を、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から派生したクラスがある場合はいつでも、それが利用可能であると期待できます。

Flynn1179

人気のリクエストで..

拡張メソッドを試してください:

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

正直に言うと、C#はそれが何の拡張であるかを正確に判断できないと思っていたので、これが機能するとは思いませんでした。どうやら、しかし、それはします!

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

派生クラスは基本クラスのプライベートメソッドをどのように呼び出すことができますか?

分類Dev

基本クラスオブジェクトへの派生クラスポインタは、どのようにして派生クラスのメソッドを呼び出すことができますか?

分類Dev

派生クラスタイプを返す基本クラスのメソッド?

分類Dev

c#基本クラスと派生クラスがインターフェイスメソッドを別々に実装できる方法はありますか?

分類Dev

派生クラスをその基本クラスのリストに追加してから、C#の基本クラスのリストから派生クラスのメソッドを呼び出すことはできますか?

分類Dev

基本クラスおよび派生クラスの外部のメソッドから派生クラスタイプを返す

分類Dev

複数の基本クラスが同じ仮想メソッドを持つことはできますか?

分類Dev

オーバーライドするメソッドは、基本クラスとは異なるアクセス指定子を持つことができますか?

分類Dev

c#基本クラスメソッドは派生クラスを返します

分類Dev

Javascriptサブクラスのインスタンスメソッドは、その親の静的メソッドを呼び出すことができますか?

分類Dev

基本クラスの静的メソッドは、Swiftのサブクラスのタイプを返します

分類Dev

基本クラスの静的メソッドは、Swiftのサブクラスのタイプを返します

分類Dev

抽象メソッドを派生クラスに実装できるようにすることはできますが、基本クラスでのみ呼び出されますか?

分類Dev

基本クラスのポインターが、派生クラスのオーバーライドされたメソッドではなく、基本クラスの純粋仮想メソッドを指すのはなぜですか?

分類Dev

派生クラスの静的メソッドをオーバーライドすることは可能ですか?

分類Dev

親クラスは孫クラスのメソッドを呼び出すことができますか?

分類Dev

クラスAはクラスBインスタンスをインスタンス化します。ClassBのインスタンスはどのようにしてクラスAのメソッドを呼び出すことができますか?

分類Dev

匿名派生クラスのアドレスを基本クラスポインタC ++に割り当てることはできますか?

分類Dev

派生型を返す基本クラスのC#メソッド

分類Dev

内部クラスは基本クラスのプライベートfinalメソッドにアクセスできますが、なぜですか?

分類Dev

クラスFooのインスタンスを静的メソッドから返すことはできません

分類Dev

C#で派生クラスインスタンスから基本メソッドを呼び出す方法は?

分類Dev

Railsは、コントローラーのインスタンスメソッド内でクラス変数を割り当てることができますか?

分類Dev

.NETメソッドに渡される変数のタイプを派生クラスではないように制限することは可能ですか?

分類Dev

基本クラスメソッドから派生型を返します

分類Dev

C ++の継承:基本クラスへの派生クラスポインタは、派生クラスメソッドを呼び出します

分類Dev

基本クラスのポインタを介して、派生クラス固有のメンバーにアクセスすることはできません

分類Dev

クラス内のメソッドはパラメーターと同じクラスを受け取ることができますか?

分類Dev

セットアップ関数で基本クラスのメソッドを呼び出すことはできますか

Related 関連記事

  1. 1

    派生クラスは基本クラスのプライベートメソッドをどのように呼び出すことができますか?

  2. 2

    基本クラスオブジェクトへの派生クラスポインタは、どのようにして派生クラスのメソッドを呼び出すことができますか?

  3. 3

    派生クラスタイプを返す基本クラスのメソッド?

  4. 4

    c#基本クラスと派生クラスがインターフェイスメソッドを別々に実装できる方法はありますか?

  5. 5

    派生クラスをその基本クラスのリストに追加してから、C#の基本クラスのリストから派生クラスのメソッドを呼び出すことはできますか?

  6. 6

    基本クラスおよび派生クラスの外部のメソッドから派生クラスタイプを返す

  7. 7

    複数の基本クラスが同じ仮想メソッドを持つことはできますか?

  8. 8

    オーバーライドするメソッドは、基本クラスとは異なるアクセス指定子を持つことができますか?

  9. 9

    c#基本クラスメソッドは派生クラスを返します

  10. 10

    Javascriptサブクラスのインスタンスメソッドは、その親の静的メソッドを呼び出すことができますか?

  11. 11

    基本クラスの静的メソッドは、Swiftのサブクラスのタイプを返します

  12. 12

    基本クラスの静的メソッドは、Swiftのサブクラスのタイプを返します

  13. 13

    抽象メソッドを派生クラスに実装できるようにすることはできますが、基本クラスでのみ呼び出されますか?

  14. 14

    基本クラスのポインターが、派生クラスのオーバーライドされたメソッドではなく、基本クラスの純粋仮想メソッドを指すのはなぜですか?

  15. 15

    派生クラスの静的メソッドをオーバーライドすることは可能ですか?

  16. 16

    親クラスは孫クラスのメソッドを呼び出すことができますか?

  17. 17

    クラスAはクラスBインスタンスをインスタンス化します。ClassBのインスタンスはどのようにしてクラスAのメソッドを呼び出すことができますか?

  18. 18

    匿名派生クラスのアドレスを基本クラスポインタC ++に割り当てることはできますか?

  19. 19

    派生型を返す基本クラスのC#メソッド

  20. 20

    内部クラスは基本クラスのプライベートfinalメソッドにアクセスできますが、なぜですか?

  21. 21

    クラスFooのインスタンスを静的メソッドから返すことはできません

  22. 22

    C#で派生クラスインスタンスから基本メソッドを呼び出す方法は?

  23. 23

    Railsは、コントローラーのインスタンスメソッド内でクラス変数を割り当てることができますか?

  24. 24

    .NETメソッドに渡される変数のタイプを派生クラスではないように制限することは可能ですか?

  25. 25

    基本クラスメソッドから派生型を返します

  26. 26

    C ++の継承:基本クラスへの派生クラスポインタは、派生クラスメソッドを呼び出します

  27. 27

    基本クラスのポインタを介して、派生クラス固有のメンバーにアクセスすることはできません

  28. 28

    クラス内のメソッドはパラメーターと同じクラスを受け取ることができますか?

  29. 29

    セットアップ関数で基本クラスのメソッドを呼び出すことはできますか

ホットタグ

アーカイブ